diff --git a/DEPS b/DEPS
index 35c6ae1..fb00c6d3 100644
--- a/DEPS
+++ b/DEPS
@@ -105,7 +105,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '9f9c2ea4282f0c332a0d55472931c39761420f54',
+  'skia_revision': '76c775f48decb142549215319ae9868a769d9902',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -117,7 +117,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '0da73fedd90022e1dd9d4611e44e6307eeedaa13',
+  'angle_revision': '607f907d47b04e9d61afafbe7af3b5e5612c5bf4',
   # 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.
@@ -129,7 +129,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': 'e8b02fb54234ed66eeab30927b4495ecc9ca1669',
+  'pdfium_revision': '7f47c50227fb4af93b58c6687786130c42b76333',
   # 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.
@@ -137,7 +137,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
-  'boringssl_revision': '13fd627449cefbae7576d4b145cb24fac303fc7d',
+  'boringssl_revision': 'ce00828c89df3d4c40de7d715b1a032eb03c525c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling google-toolbox-for-mac
   # and whatever else without interference from each other.
@@ -165,7 +165,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': 'a115d8de1c986bb73971deac71ee74a5721c32de',
+  'catapult_revision': 'cb192dee19d43e5a17bdfa8b7397122aad312bc3',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -213,7 +213,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': '2a88bcbaff3e9fa857151284d7698dad9053c1aa',
+  'spv_tools_revision': 'd73b9d8dfbf7761e3fde323af00ec18ebfc0020c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -595,7 +595,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '20afd180cccbba7fd7f3cfd082b16fe564f88eb8',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '8775060263d67635cb7c004f5cceeec68043fcf6',
       'condition': 'checkout_linux',
   },
 
@@ -954,7 +954,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '1cae4d538d01959c4912c10e735e341f63cd268d',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'a80f9bc11bcbea9fc552654281354fb696ac7b6b',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
@@ -1106,7 +1106,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '6d2f3f4cb8bac1f7c4a945c73d07a33df74f22f9',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'bfff4bac826cace3b76f8e29775009a8dad54433',
+    Var('webrtc_git') + '/src.git' + '@' + 'd2650d1a2851ab4fb14b86f04ccc4c2c09c237f5',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1137,7 +1137,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@1ed6f3571d8adb341bd41237cfc7277bc74441ca',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@64ba5a302bf0da7647c98f2aabccc42c072e1364',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/accelerators/debug_commands.cc b/ash/accelerators/debug_commands.cc
index 339526d..04b6cdb 100644
--- a/ash/accelerators/debug_commands.cc
+++ b/ash/accelerators/debug_commands.cc
@@ -21,6 +21,8 @@
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/utf_string_conversions.h"
 #include "services/ws/window_service.h"
+#include "ui/accessibility/ax_tree_id.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
 #include "ui/compositor/debug_utils.h"
 #include "ui/compositor/layer.h"
 #include "ui/display/manager/display_manager.h"
@@ -79,6 +81,9 @@
     *out << " subpixel offset=" + subpixel_position_offset.ToString();
   if (window_service && ws::WindowService::HasRemoteClient(window))
     *out << " remote_id=" << window_service->GetIdForDebugging(window);
+  std::string* tree_id = window->GetProperty(ui::kChildAXTreeID);
+  if (tree_id)
+    *out << " ax_tree_id=" << *tree_id;
   *out << '\n';
 
   for (aura::Window* child : window->children()) {
diff --git a/ash/accessibility/accessibility_controller.h b/ash/accessibility/accessibility_controller.h
index 93a9b7d..1548b80 100644
--- a/ash/accessibility/accessibility_controller.h
+++ b/ash/accessibility/accessibility_controller.h
@@ -17,7 +17,6 @@
 #include "base/time/time.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "ui/accessibility/ax_enums.mojom.h"
-#include "ui/accessibility/ax_tree_id.h"
 
 class PrefChangeRegistrar;
 class PrefRegistrySimple;
@@ -155,11 +154,6 @@
   // this controller.
   void NotifyAccessibilityStatusChanged();
 
-  void set_remote_ax_tree_id(const ui::AXTreeID& tree_id) {
-    remote_ax_tree_id_ = tree_id;
-  }
-  const ui::AXTreeID& remote_ax_tree_id() const { return remote_ax_tree_id_; }
-
   // mojom::AccessibilityController:
   void SetClient(mojom::AccessibilityControllerClientPtr client) override;
   void SetDarkenScreen(bool darken) override;
@@ -248,10 +242,6 @@
   // Used to force the backlights off to darken the screen.
   std::unique_ptr<ScopedBacklightsForcedOff> scoped_backlights_forced_off_;
 
-  // Tree ID to use for remote mojo applications.
-  // TODO(jamescook): Remove this when ash generates multiple AXTreeIDs.
-  ui::AXTreeID remote_ax_tree_id_;
-
   base::ObserverList<AccessibilityObserver>::Unchecked observers_;
 
   DISALLOW_COPY_AND_ASSIGN(AccessibilityController);
diff --git a/ash/assistant/ui/assistant_web_view.cc b/ash/assistant/ui/assistant_web_view.cc
index 3241d23..3655afa 100644
--- a/ash/assistant/ui/assistant_web_view.cc
+++ b/ash/assistant/ui/assistant_web_view.cc
@@ -101,11 +101,38 @@
   SchedulePaint();
 }
 
-void AssistantWebView::OnViewBoundsChanged(views::View* view) {
+void AssistantWebView::OnViewIsDeleting(views::View* view) {
   DCHECK_EQ(content_view_, view);
 
-  // The mask layer should always match the bounds of the content view.
-  content_view_mask_->layer()->SetBounds(content_view_->GetLocalBounds());
+  // It's possible for |content_view_| to be deleted before AssistantWebView.
+  // When this happens, we need to perform clean up on |content_view_| before
+  // it is destroyed and clear references so that we don't try to perform
+  // clean up on the destroyed instance when destroying AssistantWebView.
+  content_view_->RemoveObserver(this);
+  content_view_ = nullptr;
+}
+
+void AssistantWebView::OnWindowBoundsChanged(aura::Window* window,
+                                             const gfx::Rect& old_bounds,
+                                             const gfx::Rect& new_bounds,
+                                             ui::PropertyChangeReason reason) {
+  DCHECK_EQ(native_content_view_, window);
+
+  // The mask layer should always match the bounds of the native content view.
+  content_view_mask_->layer()->SetBounds(gfx::Rect(new_bounds.size()));
+}
+
+void AssistantWebView::OnWindowDestroying(aura::Window* window) {
+  DCHECK_EQ(native_content_view_, window);
+
+  // It's possible for |native_content_view_| to be deleted before
+  // AssistantWebView. When this happens, we need to perform clean up on
+  // |native_content_view_| before it is destroyed and clear references so that
+  // we don't try to perform clean up on the destroyed instance when destroying
+  // AssistantWebView.
+  native_content_view_->RemoveObserver(this);
+  native_content_view_->layer()->SetMaskLayer(nullptr);
+  native_content_view_ = nullptr;
 }
 
 void AssistantWebView::InitLayout() {
@@ -190,15 +217,18 @@
         embed_token.value());
     content_view_->AddObserver(this);
 
-    // The mask layer should always match the bounds of the content view. We
-    // enforce this prior to applying the mask to the |native_content_view_|
-    // layer to prevent a DCHECK failure in cc::Layer.
-    content_view_mask_->layer()->SetBounds(content_view_->GetLocalBounds());
-
-    // Apply our layer mask which enforces corner radius.
+    // Cache a reference to the content's native view and observe it so that
+    // we can monitor changes to bounds and lifecycle.
     native_content_view_ =
         app_list::AnswerCardContentsRegistry::Get()->GetNativeView(
             embed_token.value());
+    native_content_view_->AddObserver(this);
+
+    // Apply a mask layer to enforce corner radius. The mask bounds must always
+    // match the bounds of |native_content_view_|. We sync bounds prior to
+    // applying the mask to prevent a DCHECK failure in cc::Layer.
+    content_view_mask_->layer()->SetBounds(
+        gfx::Rect(native_content_view_->GetBoundsInScreen().size()));
     native_content_view_->layer()->SetMaskLayer(content_view_mask_->layer());
 
     AddChildView(content_view_);
@@ -226,6 +256,7 @@
   }
 
   if (native_content_view_) {
+    native_content_view_->RemoveObserver(this);
     native_content_view_->layer()->SetMaskLayer(nullptr);
     native_content_view_ = nullptr;
   }
diff --git a/ash/assistant/ui/assistant_web_view.h b/ash/assistant/ui/assistant_web_view.h
index 2a6869f..3d5f4a7a 100644
--- a/ash/assistant/ui/assistant_web_view.h
+++ b/ash/assistant/ui/assistant_web_view.h
@@ -13,6 +13,7 @@
 #include "ash/assistant/ui/caption_bar.h"
 #include "base/macros.h"
 #include "base/optional.h"
+#include "ui/aura/window_observer.h"
 #include "ui/views/view.h"
 #include "ui/views/view_observer.h"
 
@@ -30,6 +31,7 @@
 // web contents.
 class AssistantWebView : public views::View,
                          public views::ViewObserver,
+                         public aura::WindowObserver,
                          public AssistantControllerObserver,
                          public CaptionBarDelegate {
  public:
@@ -43,7 +45,14 @@
   void ChildPreferredSizeChanged(views::View* child) override;
 
   // views::ViewObserver:
-  void OnViewBoundsChanged(views::View* view) override;
+  void OnViewIsDeleting(views::View* view) override;
+
+  // views::WindowObserver:
+  void OnWindowBoundsChanged(aura::Window* window,
+                             const gfx::Rect& old_bounds,
+                             const gfx::Rect& new_bounds,
+                             ui::PropertyChangeReason reason) override;
+  void OnWindowDestroying(aura::Window* window) override;
 
   // CaptionBarDelegate:
   bool OnCaptionButtonPressed(CaptionButtonId id) override;
diff --git a/ash/assistant/ui/caption_bar.cc b/ash/assistant/ui/caption_bar.cc
index 3220065..01b1861 100644
--- a/ash/assistant/ui/caption_bar.cc
+++ b/ash/assistant/ui/caption_bar.cc
@@ -87,8 +87,8 @@
 void CaptionBar::InitLayout() {
   views::BoxLayout* layout_manager =
       SetLayoutManager(std::make_unique<views::BoxLayout>(
-          views::BoxLayout::Orientation::kHorizontal, gfx::Insets(),
-          kSpacingDip));
+          views::BoxLayout::Orientation::kHorizontal,
+          gfx::Insets(0, kSpacingDip), kSpacingDip));
 
   layout_manager->set_cross_axis_alignment(
       views::BoxLayout::CrossAxisAlignment::CROSS_AXIS_ALIGNMENT_CENTER);
diff --git a/ash/assistant/ui/main_stage/ui_element_container_view.cc b/ash/assistant/ui/main_stage/ui_element_container_view.cc
index 531f004..2931870 100644
--- a/ash/assistant/ui/main_stage/ui_element_container_view.cc
+++ b/ash/assistant/ui/main_stage/ui_element_container_view.cc
@@ -114,7 +114,8 @@
   }
 
   ~CardElementViewHolder() override {
-    card_element_view_->RemoveObserver(this);
+    if (card_element_view_)
+      card_element_view_->RemoveObserver(this);
   }
 
   // views::NativeViewHost:
@@ -164,7 +165,21 @@
   }
 
   // views::ViewObserver:
+  void OnViewIsDeleting(views::View* view) override {
+    DCHECK_EQ(card_element_view_, view);
+
+    // It's possible for |card_element_view_| to be destroyed before
+    // CardElementViewHolder. When this happens, we need to perform clean up
+    // prior to |card_element_view_| being destroyed and remove our cached
+    // reference to prevent additional clean up attempts on the destroyed
+    // instance when destroying CardElementViewHolder.
+    card_element_view_->RemoveObserver(this);
+    card_element_view_ = nullptr;
+  }
+
   void OnViewPreferredSizeChanged(views::View* view) override {
+    DCHECK_EQ(card_element_view_, view);
+
     gfx::Size preferred_size = view->GetPreferredSize();
 
     if (border()) {
@@ -197,7 +212,7 @@
   }
 
  private:
-  views::View* const card_element_view_;  // Owned by WebContentsManager.
+  views::View* card_element_view_;  // Owned by WebContentsManager.
 
   std::unique_ptr<views::Widget> child_widget_;
 
diff --git a/ash/public/cpp/mus_property_mirror_ash.cc b/ash/public/cpp/mus_property_mirror_ash.cc
index b9626380..ced6296c 100644
--- a/ash/public/cpp/mus_property_mirror_ash.cc
+++ b/ash/public/cpp/mus_property_mirror_ash.cc
@@ -5,6 +5,7 @@
 #include "ash/public/cpp/mus_property_mirror_ash.h"
 
 #include "ash/public/cpp/window_properties.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/wm/core/window_properties.h"
 
@@ -104,6 +105,8 @@
   } else if (key == kImmersiveWindowType) {
     root_window->SetProperty(kImmersiveWindowType,
                              window->GetProperty(kImmersiveWindowType));
+  } else if (key == ui::kChildAXTreeID) {
+    MirrorOwnedProperty(window, root_window, ui::kChildAXTreeID);
   } else if (key == wm::kWindowVisibilityAnimationDurationKey) {
     root_window->SetProperty(
         wm::kWindowVisibilityAnimationDurationKey,
diff --git a/ash/public/cpp/window_properties.cc b/ash/public/cpp/window_properties.cc
index 5612c37..910210e 100644
--- a/ash/public/cpp/window_properties.cc
+++ b/ash/public/cpp/window_properties.cc
@@ -14,6 +14,7 @@
 #include "ash/public/interfaces/window_state_type.mojom.h"
 #include "base/unguessable_token.h"
 #include "services/ws/public/mojom/window_manager.mojom.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/mus/property_converter.h"
 #include "ui/aura/window.h"
@@ -52,6 +53,8 @@
   property_converter->RegisterPrimitiveProperty(
       kCanConsumeSystemKeysKey, mojom::kCanConsumeSystemKeys_Property,
       aura::PropertyConverter::CreateAcceptAnyValueCallback());
+  property_converter->RegisterStringProperty(
+      ui::kChildAXTreeID, ws::mojom::WindowManager::kChildAXTreeID_Property);
   property_converter->RegisterPrimitiveProperty(
       kFrameActiveColorKey,
       ws::mojom::WindowManager::kFrameActiveColor_Property,
diff --git a/ash/wm/non_client_frame_controller.cc b/ash/wm/non_client_frame_controller.cc
index 6a34225..6e7f171 100644
--- a/ash/wm/non_client_frame_controller.cc
+++ b/ash/wm/non_client_frame_controller.cc
@@ -29,6 +29,7 @@
 #include "services/ws/window_service.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/accessibility/ax_tree_id.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/mus/property_converter.h"
 #include "ui/aura/mus/property_utils.h"
@@ -150,9 +151,14 @@
   // views::View:
   const char* GetClassName() const override { return "ContentsViewMus"; }
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
-    node_data->AddStringAttribute(
-        ax::mojom::StringAttribute::kChildTreeId,
-        Shell::Get()->accessibility_controller()->remote_ax_tree_id());
+    std::string* tree_id =
+        GetWidget()->GetNativeWindow()->GetProperty(ui::kChildAXTreeID);
+    // Property may not be available immediately, but focus is eventually
+    // consistent.
+    if (!tree_id)
+      return;
+    node_data->AddStringAttribute(ax::mojom::StringAttribute::kChildTreeId,
+                                  *tree_id);
     node_data->role = ax::mojom::Role::kClient;
   }
 
diff --git a/ash/wm/non_client_frame_controller_unittest.cc b/ash/wm/non_client_frame_controller_unittest.cc
index df54544..fba513c 100644
--- a/ash/wm/non_client_frame_controller_unittest.cc
+++ b/ash/wm/non_client_frame_controller_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "ash/wm/non_client_frame_controller.h"
 
-#include "ash/accessibility/accessibility_controller.h"
 #include "ash/public/cpp/ash_layout_constants.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
@@ -20,6 +19,7 @@
 #include "services/ws/test_window_tree_client.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
@@ -226,17 +226,16 @@
 }
 
 TEST_F(NonClientFrameControllerTest, ExposesChildTreeIdToAccessibility) {
-  const ui::AXTreeID ax_tree_id = ui::AXTreeID::FromString("123");
-  Shell::Get()->accessibility_controller()->set_remote_ax_tree_id(ax_tree_id);
   std::unique_ptr<aura::Window> window = CreateTestWindow();
+  const std::string ax_tree_id = "123";
+  window->SetProperty(ui::kChildAXTreeID, new std::string(ax_tree_id));
   NonClientFrameController* non_client_frame_controller =
       NonClientFrameController::Get(window.get());
   views::View* contents_view = non_client_frame_controller->GetContentsView();
   ui::AXNodeData ax_node_data;
   contents_view->GetAccessibleNodeData(&ax_node_data);
-  EXPECT_EQ(ax_tree_id,
-            ui::AXTreeID::FromString(ax_node_data.GetStringAttribute(
-                ax::mojom::StringAttribute::kChildTreeId)));
+  EXPECT_EQ(ax_tree_id, ax_node_data.GetStringAttribute(
+                            ax::mojom::StringAttribute::kChildTreeId));
   EXPECT_EQ(ax::mojom::Role::kClient, ax_node_data.role);
 }
 
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index 4f1129b9..14c3b46f 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -1975,8 +1975,10 @@
           ->GetDisplayNearestWindow(window1.get())
           .work_area();
   EXPECT_EQ(window2->GetBoundsInScreen(), work_area_bounds);
+  EXPECT_TRUE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
 
-  // 2.a. Drag the window a small amount of distance will maximize the window.
+  // 2.a. Drag the window a small amount of distance and release will maximize
+  // the window.
   DragWindowWithOffset(resizer.get(), 10, 10);
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kNone);
   // Drag the window past the indicators threshold to show the indicators.
@@ -1985,11 +1987,13 @@
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kDragArea);
   // The source window should also have been scaled.
   EXPECT_NE(window2->GetBoundsInScreen(), work_area_bounds);
+  EXPECT_FALSE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
   CompleteDrag(std::move(resizer));
   EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMaximized());
   EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMaximized());
   // The source window should have restored its bounds.
   EXPECT_EQ(window2->GetBoundsInScreen(), work_area_bounds);
+  EXPECT_TRUE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
 
   // 2.b. Drag the window long enough to snap the window. The source window will
   // snap to the other side of the splitscreen.
@@ -2003,6 +2007,7 @@
   EXPECT_EQ(window2->GetBoundsInScreen(),
             split_view_controller()->GetSnappedWindowBoundsInScreen(
                 window2.get(), SplitViewController::LEFT));
+  EXPECT_FALSE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
   DragWindowTo(resizer.get(), gfx::Point(0, 300));
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft);
   // The source window's bounds should be the same as the right snapped window
@@ -2010,6 +2015,7 @@
   EXPECT_EQ(window2->GetBoundsInScreen(),
             split_view_controller()->GetSnappedWindowBoundsInScreen(
                 window2.get(), SplitViewController::RIGHT));
+  EXPECT_FALSE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
 
   resizer->CompleteDrag();
   EXPECT_EQ(window1->GetProperty(kTabDroppedWindowStateTypeKey),
@@ -2023,6 +2029,7 @@
   EXPECT_EQ(split_view_controller()->state(),
             SplitViewController::BOTH_SNAPPED);
   EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting());
+  EXPECT_TRUE(window1->GetProperty(ash::kCanAttachToAnotherWindowKey));
 
   EndSplitView();
   EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive());
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
index d3ecf31..f2ded825 100644
--- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
+++ b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
@@ -19,7 +19,6 @@
 #include "ash/wm/tablet_mode/tablet_mode_window_state.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/layer_animation_observer.h"
-#include "ui/compositor/layer_observer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
 #include "ui/display/screen.h"
 #include "ui/views/widget/widget.h"
@@ -35,19 +34,6 @@
 // threshold.
 constexpr float kSourceWindowScale = 0.85;
 
-// Values of the blurred scrim.
-constexpr SkColor kScrimBackgroundColor = SK_ColorGRAY;
-constexpr float kScrimOpacity = 0.8;
-constexpr float kScrimBlur = 5.f;
-constexpr int kScrimTransitionInMs = 250;
-constexpr int kScrimRoundRectRadiusDp = 4;
-
-// The threshold to compute the vertical distance to create/reset the scrim. The
-// scrim is placed below the current dragged window. This value is smaller than
-// kIndicatorsThreshouldRatio to prevent the dragged window to merge back to
-// its source window during its source window's animation.
-constexpr float kScrimResetThresholdRatio = 0.05;
-
 // Returns the window selector if overview mode is active, otherwise returns
 // nullptr.
 WindowSelector* GetWindowSelector() {
@@ -56,79 +42,63 @@
              : nullptr;
 }
 
-// Creates a transparent scrim which is placed below |dragged_window|.
-std::unique_ptr<views::Widget> CreateScrim(aura::Window* dragged_window,
-                                           const gfx::Rect& bounds) {
-  std::unique_ptr<views::Widget> widget = CreateBackgroundWidget(
-      /*root_window=*/dragged_window->GetRootWindow(),
-      /*layer_type=*/ui::LAYER_TEXTURED,
-      /*background_color=*/kScrimBackgroundColor,
-      /*border_thickness=*/0,
-      /*border_radius=*/kScrimRoundRectRadiusDp,
-      /*border_color=*/SK_ColorTRANSPARENT,
-      /*initial_opacity=*/0.f,
-      /*parent=*/dragged_window->parent(),
-      /*stack_on_top=*/false);
-  widget->SetBounds(bounds);
-  return widget;
-}
-
-// When the dragged window is dragged past this value, a transparent scrim will
-// be created to place below the current dragged window to prevent the dragged
-// window to merge into any browser window beneath it and when it's dragged back
-// toward the top of the screen, the scrim will be destroyed.
-int GetScrimVerticalThreshold(const gfx::Rect& work_area_bounds) {
-  return work_area_bounds.y() +
-         work_area_bounds.height() * kScrimResetThresholdRatio;
-}
-
-// The class to observe the source window's bounds change animation. When the
-// bounds animation is running, set the dragged window not be able to attach to
-// any window to prevent it accidently attach into the animating source window.
+// The class to observe the source window's bounds change animation. It's used
+// to prevent the dragged window to merge back into the source window during
+// dragging. Only when the source window restores to its maximized window size,
+// the dragged window can be merged back into the source window.
 class SourceWindowAnimationObserver : public ui::ImplicitAnimationObserver,
-                                      public ui::LayerObserver,
                                       public aura::WindowObserver {
  public:
-  SourceWindowAnimationObserver(ui::Layer* source_window_layer,
+  SourceWindowAnimationObserver(aura::Window* source_window,
                                 aura::Window* dragged_window)
-      : source_window_layer_(source_window_layer),
-        dragged_window_(dragged_window) {
-    source_window_layer_->AddObserver(this);
+      : source_window_(source_window), dragged_window_(dragged_window) {
+    source_window_->AddObserver(this);
     dragged_window_->AddObserver(this);
   }
 
-  ~SourceWindowAnimationObserver() override {
-    if (source_window_layer_)
-      source_window_layer_->RemoveObserver(this);
-
-    if (dragged_window_) {
-      dragged_window_->RemoveObserver(this);
-      dragged_window_->ClearProperty(ash::kCanAttachToAnotherWindowKey);
-    }
-  }
+  ~SourceWindowAnimationObserver() override { StopObserving(); }
 
   // ui::ImplicitAnimationObserver:
   void OnLayerAnimationStarted(ui::LayerAnimationSequence* sequence) override {
-    DCHECK(dragged_window_);
+    DCHECK(dragged_window_ && source_window_);
     dragged_window_->SetProperty(ash::kCanAttachToAnotherWindowKey, false);
   }
 
-  void OnImplicitAnimationsCompleted() override { delete this; }
-
-  // ui::LayerObserver:
-  void LayerDestroyed(ui::Layer* layer) override {
-    DCHECK_EQ(source_window_layer_, layer);
-    delete this;
+  void OnImplicitAnimationsCompleted() override {
+    DCHECK(dragged_window_ && source_window_);
+    // When arriving here, we know the source window bounds change animation
+    // just ended. Only clear the property ash::kCanAttachToAnotherWindowKey if
+    // the source window bounds restores to its maximized window size.
+    gfx::Rect work_area_bounds = display::Screen::GetScreen()
+                                     ->GetDisplayNearestWindow(source_window_)
+                                     .work_area();
+    ::wm::ConvertRectFromScreen(source_window_->parent(), &work_area_bounds);
+    if (source_window_->bounds() == work_area_bounds)
+      StopObserving();
   }
 
   // aura::WindowObserver:
   void OnWindowDestroying(aura::Window* window) override {
-    DCHECK_EQ(dragged_window_, window);
-    delete this;
+    DCHECK(window == source_window_ || window == dragged_window_);
+    StopObserving();
   }
 
  private:
-  ui::Layer* source_window_layer_;
+  void StopObserving() {
+    StopObservingImplicitAnimations();
+    if (source_window_) {
+      source_window_->RemoveObserver(this);
+      source_window_ = nullptr;
+    }
+
+    if (dragged_window_) {
+      dragged_window_->RemoveObserver(this);
+      dragged_window_->ClearProperty(ash::kCanAttachToAnotherWindowKey);
+      dragged_window_ = nullptr;
+    }
+  }
+
+  aura::Window* source_window_;
   aura::Window* dragged_window_;
 
   DISALLOW_COPY_AND_ASSIGN(SourceWindowAnimationObserver);
@@ -291,9 +261,6 @@
 
   // Update the source window if necessary.
   UpdateSourceWindow(location_in_screen);
-
-  // Update the scrim that beneath the dragged window if necessary.
-  UpdateScrim(location_in_screen);
 }
 
 void TabletModeBrowserWindowDragDelegate::EndingForDraggedWindow(
@@ -312,7 +279,6 @@
     TabletModeWindowState::UpdateWindowPosition(
         wm::GetWindowState(source_window));
   }
-  scrim_.reset();
   windows_hider_.reset();
 }
 
@@ -373,95 +339,12 @@
         source_window->layer()->GetAnimator());
     settings.SetPreemptionStrategy(
         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
-    settings.AddObserver(new SourceWindowAnimationObserver(
-        source_window->layer(), dragged_window_));
+    source_window_bounds_observer_ =
+        std::make_unique<SourceWindowAnimationObserver>(source_window,
+                                                        dragged_window_);
+    settings.AddObserver(source_window_bounds_observer_.get());
     source_window->SetBounds(expected_bounds);
   }
 }
 
-void TabletModeBrowserWindowDragDelegate::UpdateScrim(
-    const gfx::Point& location_in_screen) {
-  const gfx::Rect work_area_bounds =
-      display::Screen::GetScreen()
-          ->GetDisplayNearestWindow(dragged_window_)
-          .work_area();
-  if (location_in_screen.y() < GetScrimVerticalThreshold(work_area_bounds) ||
-      location_in_screen.y() >= work_area_bounds.bottom()) {
-    // Remove |scrim_| entirely so that the dragged window can be merged back
-    // to the source window when the dragged window is dragged back toward the
-    // top area of the screen. Also remove |scrim_| if the dragged window is
-    // dragged to the bottom of the screen.
-    scrim_.reset();
-    return;
-  }
-
-  // If overview mode is active, do not show the scrim on the overview side of
-  // the screen.
-  if (Shell::Get()->window_selector_controller()->IsSelecting()) {
-    WindowGrid* window_grid = GetWindowSelector()->GetGridWithRootWindow(
-        dragged_window_->GetRootWindow());
-    if (window_grid && window_grid->bounds().Contains(location_in_screen)) {
-      scrim_.reset();
-      return;
-    }
-  }
-
-  SplitViewController::SnapPosition snap_position =
-      GetSnapPosition(location_in_screen);
-  gfx::Rect expected_bounds(work_area_bounds);
-  if (split_view_controller_->IsSplitViewModeActive()) {
-    expected_bounds = split_view_controller_->GetSnappedWindowBoundsInScreen(
-        dragged_window_, snap_position);
-  } else {
-    expected_bounds.Inset(kHighlightScreenEdgePaddingDp,
-                          kHighlightScreenEdgePaddingDp);
-  }
-
-  bool should_show_blurred_scrim = false;
-  if (location_in_screen.y() >=
-      GetMaximizeVerticalThreshold(work_area_bounds)) {
-    if (split_view_controller_->IsSplitViewModeActive() !=
-        (snap_position == SplitViewController::NONE)) {
-      should_show_blurred_scrim = true;
-    }
-  }
-  // When the event is between |indicators_vertical_threshold| and
-  // |maximize_vertical_threshold|, the scrim is still shown but is invisible
-  // to the user (transparent). It's needed to prevent the dragged window to
-  // merge into the scaled down source window.
-  ShowScrim(should_show_blurred_scrim ? kScrimOpacity : 0.f,
-            should_show_blurred_scrim ? kScrimBlur : 0.f, expected_bounds);
-}
-
-void TabletModeBrowserWindowDragDelegate::ShowScrim(
-    float opacity,
-    float blur,
-    const gfx::Rect& bounds_in_screen) {
-  gfx::Rect bounds(bounds_in_screen);
-  ::wm::ConvertRectFromScreen(dragged_window_->parent(), &bounds);
-
-  if (scrim_ && scrim_->GetLayer()->GetTargetOpacity() == opacity &&
-      scrim_->GetNativeWindow()->bounds() == bounds) {
-    return;
-  }
-
-  if (!scrim_)
-    scrim_ = CreateScrim(dragged_window_, bounds);
-  dragged_window_->parent()->StackChildBelow(scrim_->GetNativeWindow(),
-                                             dragged_window_);
-  scrim_->GetLayer()->SetBackgroundBlur(blur);
-
-  if (scrim_->GetNativeWindow()->bounds() != bounds) {
-    scrim_->SetOpacity(0.f);
-    scrim_->SetBounds(bounds);
-  }
-  ui::ScopedLayerAnimationSettings animation(scrim_->GetLayer()->GetAnimator());
-  animation.SetTweenType(gfx::Tween::EASE_IN_OUT);
-  animation.SetTransitionDuration(
-      base::TimeDelta::FromMilliseconds(kScrimTransitionInMs));
-  animation.SetPreemptionStrategy(
-      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
-  scrim_->SetOpacity(opacity);
-}
-
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h
index d568788..ace3091 100644
--- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h
+++ b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.h
@@ -8,15 +8,12 @@
 #include "ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h"
 #include "base/macros.h"
 
-namespace views {
-class Widget;
-}  // namespace views
-
 namespace ash {
 
 // The drag delegate for browser windows. It not only includes the logic in
 // TabletModeWindowDragDelegate, but also has special logic for browser windows,
-// e.g., scales the source window, shows/hides the blurred background, etc.
+// e.g., scales the source window, shows/hides the other windows below the
+// source window.
 class TabletModeBrowserWindowDragDelegate
     : public TabletModeWindowDragDelegate {
  public:
@@ -40,18 +37,6 @@
   // current drag location for the dragged window.
   void UpdateSourceWindow(const gfx::Point& location_in_screen);
 
-  // Shows/Hides/Destroies the scrim widget |scrim_| based on the current
-  // location |location_in_screen|.
-  void UpdateScrim(const gfx::Point& location_in_screen);
-
-  // Shows the scrim with the specified opacity, blur and expected bounds.
-  void ShowScrim(float opacity, float blur, const gfx::Rect& bounds_in_screen);
-
-  // A widget placed below the current dragged window to show the blurred or
-  // transparent background and to prevent the dragged window merge into any
-  // browser window beneath it during dragging.
-  std::unique_ptr<views::Widget> scrim_;
-
   // It's used to hide all visible windows if the source window needs to be
   // scaled up/down during dragging a tab out of the source window. It also
   // hides the home launcher if home launcher is enabled, blurs and darkens the
@@ -59,6 +44,13 @@
   // destruction.
   std::unique_ptr<WindowsHider> windows_hider_;
 
+  // The observer to observe the source window's bounds change animation during
+  // dragging. It's used to prevent the dragged window to merge back into the
+  // source window during dragging. Only when the source window restores to its
+  // maximized window size, the dragged window can be merged back into the
+  // source window.
+  std::unique_ptr<ui::ImplicitAnimationObserver> source_window_bounds_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(TabletModeBrowserWindowDragDelegate);
 };
 
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
index fee68f8f..e21fa511f 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
@@ -29,10 +29,6 @@
 // tablet mode.
 constexpr float kIndicatorsThresholdRatio = 0.1;
 
-// The threshold to compute the vertical distance to hide the drag indicators
-// and maximize the dragged window after the drag ends.
-constexpr float kMaximizeThresholdRatio = 0.4;
-
 // Returns the window selector if overview mode is active, otherwise returns
 // nullptr.
 WindowSelector* GetWindowSelector() {
@@ -245,16 +241,6 @@
     return IndicatorState::kNone;
   }
 
-  // If the event location has passed the maximize vertical threshold, and the
-  // event location is not in snap indicator area, and overview mode is not
-  // active at the moment, do not show the drag indicators.
-  if (location_in_screen.y() >=
-          GetMaximizeVerticalThreshold(work_area_bounds) &&
-      snap_position == SplitViewController::NONE &&
-      !Shell::Get()->window_selector_controller()->IsSelecting()) {
-    return IndicatorState::kNone;
-  }
-
   // No top drag indicator if in portrait screen orientation.
   if (split_view_controller_->IsCurrentScreenOrientationLandscape())
     return can_snap ? IndicatorState::kDragArea : IndicatorState::kCannotSnap;
@@ -274,12 +260,6 @@
          work_area_bounds.height() * kIndicatorsThresholdRatio;
 }
 
-int TabletModeWindowDragDelegate::GetMaximizeVerticalThreshold(
-    const gfx::Rect& work_area_bounds) const {
-  return work_area_bounds.y() +
-         work_area_bounds.height() * kMaximizeThresholdRatio;
-}
-
 SplitViewController::SnapPosition TabletModeWindowDragDelegate::GetSnapPosition(
     const gfx::Point& location_in_screen) const {
   gfx::Rect work_area_bounds = display::Screen::GetScreen()
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h
index 075251cd..36a6ec4 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.h
@@ -81,10 +81,6 @@
   // will show up.
   int GetIndicatorsVerticalThreshold(const gfx::Rect& work_area_bounds) const;
 
-  // When the dragged window is dragged past this value, a blured scrim will
-  // show up, indicating the dragged window will be maximized after releasing.
-  int GetMaximizeVerticalThreshold(const gfx::Rect& work_area_bounds) const;
-
   // Gets the desired snap position for |location_in_screen|.
   SplitViewController::SnapPosition GetSnapPosition(
       const gfx::Point& location_in_screen) const;
diff --git a/base/android/scoped_hardware_buffer_handle.cc b/base/android/scoped_hardware_buffer_handle.cc
index 55b0a70..315fba8a 100644
--- a/base/android/scoped_hardware_buffer_handle.cc
+++ b/base/android/scoped_hardware_buffer_handle.cc
@@ -28,6 +28,13 @@
   return ScopedHardwareBufferHandle(buffer);
 }
 
+// static
+ScopedHardwareBufferHandle ScopedHardwareBufferHandle::Create(
+    AHardwareBuffer* buffer) {
+  AndroidHardwareBufferCompat::GetInstance().Acquire(buffer);
+  return ScopedHardwareBufferHandle(buffer);
+}
+
 ScopedHardwareBufferHandle& ScopedHardwareBufferHandle::operator=(
     ScopedHardwareBufferHandle&& other) {
   reset();
diff --git a/base/android/scoped_hardware_buffer_handle.h b/base/android/scoped_hardware_buffer_handle.h
index b8121ae..6d2a7d5 100644
--- a/base/android/scoped_hardware_buffer_handle.h
+++ b/base/android/scoped_hardware_buffer_handle.h
@@ -30,6 +30,9 @@
   // acquire a new reference.
   static ScopedHardwareBufferHandle Adopt(AHardwareBuffer* buffer);
 
+  // Adds a reference to |buffer| managed by this handle.
+  static ScopedHardwareBufferHandle Create(AHardwareBuffer* buffer);
+
   // Takes ownership of |other|'s buffer reference. Does NOT acquire a new one.
   ScopedHardwareBufferHandle& operator=(ScopedHardwareBufferHandle&& other);
 
diff --git a/build/chromeos/run_vm_test.py b/build/chromeos/run_vm_test.py
index 8d574e3..bc374b49 100755
--- a/build/chromeos/run_vm_test.py
+++ b/build/chromeos/run_vm_test.py
@@ -70,19 +70,7 @@
           '--results-dest-dir', args.vm_logs_dir,
       ]
 
-    self._test_env = os.environ.copy()
-    # deploy_chrome needs a set of GN args used to build chrome to determine if
-    # certain libraries need to be pushed to the VM. It looks for the args via
-    # an env var. To trigger the default deploying behavior, give it a dummy set
-    # of args.
-    # TODO(crbug.com/823996): Make the GN-dependent deps controllable via cmd
-    # line args.
-    if not self._test_env.get('GN_ARGS'):
-      self._test_env['GN_ARGS'] = 'is_chromeos = true'
-    if not self._test_env.get('USE'):
-      self._test_env['USE'] = 'highdpi'
-    self._test_env['PATH'] = (
-        self._test_env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin'))
+    self._test_env = setup_env()
 
   @property
   def suite_name(self):
@@ -402,23 +390,12 @@
   if args.verbose:
     cros_run_vm_test_cmd.append('--debug')
 
-  test_env = os.environ.copy()
+  test_env = setup_env()
   if args.deploy_chrome:
     cros_run_vm_test_cmd += [
         '--deploy',
         '--build-dir', os.path.abspath(args.path_to_outdir),
     ]
-    # If we're deploying, push chromite/bin's deploy_chrome onto PATH.
-    test_env['PATH'] = (
-        test_env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin'))
-    # deploy_chrome needs a set of GN args used to build chrome to determine if
-    # certain libraries need to be pushed to the VM. It looks for the args via
-    # an env var. To trigger the default deploying behavior, give it a dummy set
-    # of args.
-    # TODO(crbug.com/823996): Make the GN-dependent deps controllable via cmd
-    # line args.
-    if not test_env.get('GN_ARGS'):
-      test_env['GN_ARGS'] = 'is_chromeos = true'
 
   cros_run_vm_test_cmd += [
       '--host-cmd',
@@ -432,6 +409,24 @@
       cros_run_vm_test_cmd, stdout=sys.stdout, stderr=sys.stderr, env=test_env)
 
 
+def setup_env():
+  """Returns a copy of the current env with some needed vars added."""
+  env = os.environ.copy()
+  # Some chromite scripts expect chromite/bin to be on PATH.
+  env['PATH'] = env['PATH'] + ':' + os.path.join(CHROMITE_PATH, 'bin')
+  # deploy_chrome needs a set of GN args used to build chrome to determine if
+  # certain libraries need to be pushed to the VM. It looks for the args via
+  # an env var. To trigger the default deploying behavior, give it a dummy set
+  # of args.
+  # TODO(crbug.com/823996): Make the GN-dependent deps controllable via cmd
+  # line args.
+  if not env.get('GN_ARGS'):
+    env['GN_ARGS'] = 'enable_nacl = true'
+  if not env.get('USE'):
+    env['USE'] = 'highdpi'
+  return env
+
+
 def add_common_args(parser):
    parser.add_argument(
        '--cros-cache', type=str, default=DEFAULT_CROS_CACHE,
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index 5265adb..e86d2e4 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -52,7 +52,8 @@
   # Enables support for ThinLTO, which links 3x-10x faster than full LTO. See
   # also http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html
   # TODO(https://crbug.com/887272): Reenable on is_android && is_official_build
-  use_thin_lto = is_cfi
+  use_thin_lto =
+      is_cfi || (is_android && is_official_build && llvm_force_head_revision)
 
   # Tell VS to create a PDB that references information in .obj files rather
   # than copying it all. This should improve linker performance. mspdbcmf.exe
diff --git a/cc/resources/resource_pool_unittest.cc b/cc/resources/resource_pool_unittest.cc
index 8b6cf746..8251332 100644
--- a/cc/resources/resource_pool_unittest.cc
+++ b/cc/resources/resource_pool_unittest.cc
@@ -668,7 +668,7 @@
 
   // These values are all non-default values so we can tell they are propagated.
   gfx::Size size(100, 101);
-  viz::ResourceFormat format = viz::ETC1;
+  viz::ResourceFormat format = viz::RGBA_4444;
   EXPECT_NE(gfx::BufferFormat::RGBA_8888, viz::BufferFormat(format));
   gfx::ColorSpace color_space = gfx::ColorSpace::CreateSRGB();
   uint32_t target = 5;
diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
index 666b849d..7c9b86cb 100644
--- a/cc/trees/draw_property_utils.cc
+++ b/cc/trees/draw_property_utils.cc
@@ -29,6 +29,11 @@
 
 namespace {
 
+static gfx::Rect ToEnclosingClipRect(const gfx::RectF& clip_rect) {
+  constexpr float kClipError = 0.00001f;
+  return gfx::ToEnclosingRectIgnoringError(clip_rect, kClipError);
+}
+
 static bool IsRootLayer(const Layer* layer) {
   return !layer->parent();
 }
@@ -129,10 +134,11 @@
                                           const PropertyTrees* property_trees,
                                           int target_transform_id,
                                           int target_effect_id) {
-  if (clip_node->transform_id != target_transform_id)
+  if (clip_node->transform_id != target_transform_id) {
     return ComputeLocalRectInTargetSpace(clip_node->clip, property_trees,
                                          clip_node->transform_id,
                                          target_transform_id, target_effect_id);
+  }
 
   const EffectTree& effect_tree = property_trees->effect_tree;
   gfx::RectF current_clip = clip_node->clip;
@@ -183,7 +189,7 @@
       // Do the expansion.
       gfx::RectF expanded_clip_in_expanding_space =
           gfx::RectF(clip_node->clip_expander->MapRectReverse(
-              gfx::ToEnclosingRect(accumulated_clip_rect_in_expanding_space),
+              ToEnclosingClipRect(accumulated_clip_rect_in_expanding_space),
               property_trees));
 
       // Put the expanded clip back into the original target space.
@@ -557,13 +563,13 @@
   bool include_expanding_clips = false;
   if (render_surface->EffectTreeIndex() == EffectTree::kContentsRootNodeId) {
     render_surface->SetClipRect(
-        gfx::ToEnclosingRect(clip_tree.Node(effect_node->clip_id)->clip));
+        ToEnclosingClipRect(clip_tree.Node(effect_node->clip_id)->clip));
   } else {
     ConditionalClip accumulated_clip_rect =
         ComputeAccumulatedClip(property_trees, include_expanding_clips,
                                effect_node->clip_id, target_node->id);
     render_surface->SetClipRect(
-        gfx::ToEnclosingRect(accumulated_clip_rect.clip_rect));
+        ToEnclosingClipRect(accumulated_clip_rect.clip_rect));
   }
 }
 
@@ -641,7 +647,7 @@
   gfx::RectF clip_in_layer_space = accumulated_clip_in_layer_space.clip_rect;
   clip_in_layer_space.Offset(-layer->offset_to_transform_parent());
 
-  gfx::Rect visible_rect = gfx::ToEnclosingRect(clip_in_layer_space);
+  gfx::Rect visible_rect = ToEnclosingClipRect(clip_in_layer_space);
   visible_rect.Intersect(layer_content_rect);
   return visible_rect;
 }
@@ -916,7 +922,7 @@
     // is_clipped should be set before visible rect computation as it is used
     // there.
     layer->draw_properties().is_clipped = clip.is_clipped;
-    layer->draw_properties().clip_rect = gfx::ToEnclosingRect(clip.clip_rect);
+    layer->draw_properties().clip_rect = ToEnclosingClipRect(clip.clip_rect);
     layer->draw_properties().visible_layer_rect =
         LayerVisibleRect(property_trees, layer);
   }
@@ -949,8 +955,7 @@
   // is_clipped should be set before visible rect computation as it is used
   // there.
   mask_layer->draw_properties().is_clipped = clip.is_clipped;
-  mask_layer->draw_properties().clip_rect =
-      gfx::ToEnclosingRect(clip.clip_rect);
+  mask_layer->draw_properties().clip_rect = ToEnclosingClipRect(clip.clip_rect);
   // Calculate actual visible layer rect for mask layers, since we could have
   // tiled mask layers and the tile manager would need this info for rastering.
   mask_layer->draw_properties().visible_layer_rect =
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 285ed7b67..d5d6073 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -4783,7 +4783,7 @@
 }
 
 void LayerTreeHostImpl::SetFullViewportDamage() {
-  SetViewportDamage(active_tree_->GetDeviceViewport());
+  SetViewportDamage(gfx::Rect(active_tree_->GetDeviceViewport().size()));
 }
 
 bool LayerTreeHostImpl::AnimatePageScale(base::TimeTicks monotonic_time) {
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index b9d0f9b..c384550 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -304,6 +304,10 @@
     resourceless_software_draw_ = true;
   }
 
+  const gfx::Rect& viewport_damage_rect_for_testing() const {
+    return viewport_damage_rect_;
+  }
+
   virtual void DidSendBeginMainFrame() {}
   virtual void BeginMainFrameAborted(
       CommitEarlyOutReason reason,
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index f22b1f7..cfff074 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -11399,6 +11399,28 @@
   EXPECT_FALSE(last_on_draw_frame_->has_no_damage);
 }
 
+// This test verifies that the viewport damage rect is the full viewport and not
+// just part of the viewport in the presence of an external viewport.
+TEST_F(LayerTreeHostImplTest, FullViewportDamageAfterOnDraw) {
+  SetupRootLayerImpl(LayerImpl::Create(host_impl_->active_tree(), 1));
+  host_impl_->active_tree()->BuildPropertyTreesForTesting();
+
+  const gfx::Size viewport_size(100, 100);
+  host_impl_->active_tree()->SetDeviceViewportSize(viewport_size);
+
+  const gfx::Transform draw_transform;
+  const gfx::Rect draw_viewport(gfx::Point(5, 5), viewport_size);
+  bool resourceless_software_draw = false;
+
+  host_impl_->OnDraw(draw_transform, draw_viewport, resourceless_software_draw,
+                     false);
+  EXPECT_EQ(draw_viewport, host_impl_->active_tree()->GetDeviceViewport());
+
+  host_impl_->SetFullViewportDamage();
+  EXPECT_EQ(gfx::Rect(viewport_size),
+            host_impl_->viewport_damage_rect_for_testing());
+}
+
 class ResourcelessSoftwareLayerTreeHostImplTest : public LayerTreeHostImplTest {
  protected:
   std::unique_ptr<LayerTreeFrameSink> CreateLayerTreeFrameSink() override {
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 991aaa7..042e90c 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -530,10 +530,8 @@
     <dimen name="chip_list_padding">2.5dp</dimen>
 
     <!-- Download manager dimensions -->
-    <dimen name="download_manager_image_width">150dp</dimen>
+    <dimen name="download_manager_ideal_image_width">150dp</dimen>
     <dimen name="download_manager_image_padding">2dp</dimen>
-    <dimen name="download_manager_generic_thumbnail_size">36dp</dimen>
-    <dimen name="download_manager_prefetch_thumbnail_size">114dp</dimen>
     <dimen name="download_manager_prefetch_horizontal_margin">16dp</dimen>
     <dimen name="download_manager_prefetch_vertical_margin">12dp</dimen>
     <dimen name="download_manager_section_title_padding_top">16dp</dimen>
diff --git a/chrome/android/java/res/xml/data_reduction_preferences_off.xml b/chrome/android/java/res/xml/data_reduction_preferences_off.xml
index 3cd5b09f..1c8bcb4 100644
--- a/chrome/android/java/res/xml/data_reduction_preferences_off.xml
+++ b/chrome/android/java/res/xml/data_reduction_preferences_off.xml
@@ -10,10 +10,6 @@
         android:title="@string/data_reduction_benefits_description" />
     <org.chromium.chrome.browser.preferences.TextMessagePreference
         android:title="@string/data_reduction_description" />
-    <org.chromium.chrome.browser.preferences.TextMessagePreference
-        android:title="@string/safe_browsing_description" />
-    <org.chromium.chrome.browser.preferences.TextMessagePreference
-        android:title="@string/data_reduction_caveats_description" />
     <org.chromium.chrome.browser.preferences.LearnMorePreference
         android:key="data_reduction_learn_more"
         app:helpContext="@string/help_context_data_reduction" />
diff --git a/chrome/android/java/res_download/drawable/circular_progress_bar_pause_tiny.xml b/chrome/android/java/res_download/drawable/circular_progress_bar_pause_tiny.xml
new file mode 100644
index 0000000..fd4de3d
--- /dev/null
+++ b/chrome/android/java/res_download/drawable/circular_progress_bar_pause_tiny.xml
@@ -0,0 +1,19 @@
+<?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. -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:drawable="@drawable/ic_pause_white_24dp" />
+    <item>
+        <shape
+            android:innerRadius="14dp"
+            android:thickness="0dp"
+            android:shape="ring"
+            android:useLevel="false">
+            <stroke
+                android:width="2dp"
+                android:color="@android:color/white" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/chrome/android/java/res_download/drawable/circular_progress_bar_resume_tiny.xml b/chrome/android/java/res_download/drawable/circular_progress_bar_resume_tiny.xml
new file mode 100644
index 0000000..902480e
--- /dev/null
+++ b/chrome/android/java/res_download/drawable/circular_progress_bar_resume_tiny.xml
@@ -0,0 +1,19 @@
+<?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. -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+    <item android:drawable="@drawable/ic_play_arrow_white_24dp" />
+    <item>
+        <shape
+            android:innerRadius="14dp"
+            android:thickness="0dp"
+            android:shape="ring"
+            android:useLevel="false">
+            <stroke
+                android:width="2dp"
+                android:color="@android:color/white" />
+        </shape>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/chrome/android/java/res_download/layout/download_manager_generic_item.xml b/chrome/android/java/res_download/layout/download_manager_generic_item.xml
index 581a439..bcf4888e 100644
--- a/chrome/android/java/res_download/layout/download_manager_generic_item.xml
+++ b/chrome/android/java/res_download/layout/download_manager_generic_item.xml
@@ -16,23 +16,22 @@
     app:columnCount="3"
     app:rowCount="2">
 
-    <android.support.v7.widget.AppCompatImageView
+    <org.chromium.chrome.browser.download.home.list.view.AsyncImageView
         android:id="@+id/thumbnail"
-        android:layout_width="@dimen/download_manager_generic_thumbnail_size"
-        android:layout_height="@dimen/download_manager_generic_thumbnail_size"
+        android:layout_width="36dp"
+        android:layout_height="36dp"
         android:layout_marginStart="16dp"
         android:layout_marginEnd="16dp"
         android:scaleType="center"
         app:layout_column="0"
         app:layout_row="0"
         app:layout_rowSpan="2"
-        app:layout_gravity="center_vertical"
-        app:tint="@color/dark_mode_tint" />
+        app:layout_gravity="center_vertical" />
 
     <org.chromium.chrome.browser.download.home.view.SelectionView
         android:id="@+id/selection"
-        android:layout_width="@dimen/download_manager_generic_thumbnail_size"
-        android:layout_height="@dimen/download_manager_generic_thumbnail_size"
+        android:layout_width="36dp"
+        android:layout_height="36dp"
         android:layout_marginStart="16dp"
         android:layout_marginEnd="16dp"
         app:layout_column="0"
diff --git a/chrome/android/java/res_download/layout/download_manager_image_item.xml b/chrome/android/java/res_download/layout/download_manager_image_item.xml
index 264f2baa..fad5d3f 100644
--- a/chrome/android/java/res_download/layout/download_manager_image_item.xml
+++ b/chrome/android/java/res_download/layout/download_manager_image_item.xml
@@ -4,7 +4,7 @@
      found in the LICENSE file.
 -->
 
-<FrameLayout
+<org.chromium.chrome.browser.download.home.list.view.AspectRatioFrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
@@ -13,19 +13,18 @@
     android:clickable="true"
     android:background="@color/modern_grey_100" >
 
-    <org.chromium.chrome.browser.download.home.list.view.SquareAsyncImageView
+    <org.chromium.chrome.browser.download.home.list.view.AsyncImageView
         android:id="@+id/thumbnail"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
         android:background="@color/modern_grey_300"
         android:scaleType="centerCrop"
         android:layout_gravity="center"
         android:adjustViewBounds="true"
         style="@style/AsyncImageView"
-        tools:ignore="ContentDescription" />
+        tools:ignore="ContentDescription"
+        app:layout_aspectRatio="100%" />
 
     <org.chromium.chrome.browser.download.home.view.SelectionView
         android:id="@+id/selection"
         style="@style/DownloadItemSelectionView"/>
-
-</FrameLayout>
+</org.chromium.chrome.browser.download.home.list.view.AspectRatioFrameLayout>
diff --git a/chrome/android/java/res_download/layout/download_manager_in_progress_image_item.xml b/chrome/android/java/res_download/layout/download_manager_in_progress_image_item.xml
new file mode 100644
index 0000000..a0e5f03
--- /dev/null
+++ b/chrome/android/java/res_download/layout/download_manager_in_progress_image_item.xml
@@ -0,0 +1,55 @@
+<?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.download.home.list.view.AspectRatioFrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clickable="true"
+    android:background="@color/modern_grey_100" >
+
+    <!-- Set the src attribute in Java to wrap the drawable properly. -->
+    <ImageView
+        android:id="@+id/placeholder"
+        android:layout_width="match_parent"
+        app:layout_aspectRatio="100%"
+        android:scaleType="centerCrop"
+        android:layout_gravity="center"
+        android:adjustViewBounds="true"
+        tools:ignore="ContentDescription" />
+
+    <android.support.v7.widget.AppCompatImageButton
+        android:id="@+id/cancel_button"
+        android:layout_width="36dp"
+        android:layout_height="36dp"
+        android:layout_gravity="end|top"
+        android:background="?attr/selectableItemBackground"
+        android:contentDescription="@string/download_notification_cancel_button"
+        android:src="@drawable/btn_close"
+        app:tint="@color/modern_blue_600" />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="fill_horizontal|bottom"
+        android:orientation="horizontal">
+        <TextView
+            android:id="@+id/caption"
+            style="@style/DownloadItemText"
+            android:textAppearance="@style/BlackHint2"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_gravity="center_vertical"
+            android:paddingStart="4dp" />
+        <org.chromium.chrome.browser.download.home.list.view.CircularProgressView
+            android:id="@+id/action_button"
+            android:layout_gravity="center_vertical"
+            style="@style/TinyCircularProgress" />
+    </LinearLayout>
+</org.chromium.chrome.browser.download.home.list.view.AspectRatioFrameLayout>
diff --git a/chrome/android/java/res_download/layout/download_manager_in_progress_video_item.xml b/chrome/android/java/res_download/layout/download_manager_in_progress_video_item.xml
index 116f9e8..02427a83 100644
--- a/chrome/android/java/res_download/layout/download_manager_in_progress_video_item.xml
+++ b/chrome/android/java/res_download/layout/download_manager_in_progress_video_item.xml
@@ -15,6 +15,7 @@
     app:columnCount="2"
     app:rowCount="3">
 
+    <!-- Set the src attribute in Java to wrap the drawable properly. -->
     <org.chromium.chrome.browser.download.home.list.view.ForegroundRoundedCornerImageView
         android:id="@+id/thumbnail"
         android:layout_width="match_parent"
diff --git a/chrome/android/java/res_download/layout/download_manager_prefetch_item.xml b/chrome/android/java/res_download/layout/download_manager_prefetch_item.xml
index e933e5a..5b29fd93 100644
--- a/chrome/android/java/res_download/layout/download_manager_prefetch_item.xml
+++ b/chrome/android/java/res_download/layout/download_manager_prefetch_item.xml
@@ -15,7 +15,7 @@
     app:columnCount="4"
     app:rowCount="4">
 
-    <org.chromium.ui.widget.RoundedCornerImageView
+    <org.chromium.chrome.browser.download.home.list.view.AsyncImageView
         android:id="@+id/thumbnail"
         android:layout_width="113dp"
         android:layout_height="112dp"
@@ -29,6 +29,7 @@
         app:layout_rowSpan="4"
         app:cornerRadiusTopStart="@dimen/download_manager_prefetch_thumbnail_corner_radius"
         app:cornerRadiusBottomStart="@dimen/download_manager_prefetch_thumbnail_corner_radius"
+        style="@style/AsyncImageView"
         tools:ignore="ContentDescription" />
 
     <org.chromium.chrome.browser.download.home.view.SelectionView
diff --git a/chrome/android/java/res_download/values-v17/attrs.xml b/chrome/android/java/res_download/values-v17/attrs.xml
index d98896f..4b5e921 100644
--- a/chrome/android/java/res_download/values-v17/attrs.xml
+++ b/chrome/android/java/res_download/values-v17/attrs.xml
@@ -18,4 +18,7 @@
     <declare-styleable name="ForegroundRoundedCornerImageView">
         <attr name="foregroundCompat" format="reference" />
     </declare-styleable>
+    <declare-styleable name="AspectRatioFrameLayout_Layout">
+        <attr name="layout_aspectRatio" format="fraction" />
+    </declare-styleable>
 </resources>
\ No newline at end of file
diff --git a/chrome/android/java/res_download/values-v17/styles.xml b/chrome/android/java/res_download/values-v17/styles.xml
index 2eac51e..72599ee 100644
--- a/chrome/android/java/res_download/values-v17/styles.xml
+++ b/chrome/android/java/res_download/values-v17/styles.xml
@@ -74,6 +74,16 @@
     </style>
 
     <!-- Download Home V2 Snowflake Contender Styles -->
+    <style name="TinyCircularProgress">
+        <item name="android:layout_width">36dp</item>
+        <item name="android:layout_height">36dp</item>
+        <item name="android:tint">@color/modern_blue_600</item>
+        <item name="android:background">?attr/selectableItemBackground</item>
+        <item name="resumeSrc">@drawable/circular_progress_bar_resume_tiny</item>
+        <!-- TODO(883387): Support retrying failed downloads. -->
+        <item name="retrySrc">@drawable/circular_progress_bar_resume_tiny</item>
+        <item name="pauseSrc">@drawable/circular_progress_bar_pause_tiny</item>
+    </style>
     <style name="SmallCircularProgress">
         <item name="android:layout_width">36dp</item>
         <item name="android:layout_height">36dp</item>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
index aeaff82358..cb051ae 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiController.java
@@ -8,6 +8,7 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.chrome.browser.autofill.PersonalDataManager;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
@@ -19,7 +20,6 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -108,6 +108,16 @@
         nativeOnScriptSelected(mUiControllerAndroid, scriptPath);
     }
 
+    @Override
+    public void onAddressSelected(String guid) {
+        nativeOnAddressSelected(mUiControllerAndroid, guid);
+    }
+
+    @Override
+    public void onCardSelected(String guid) {
+        nativeOnCardSelected(mUiControllerAndroid, guid);
+    }
+
     /** Return the value if the given boolean parameter from the extras. */
     private static boolean getBooleanParameter(Bundle extras, String parameterName) {
         return extras.getBoolean(INTENT_EXTRA_PREFIX + parameterName, false);
@@ -151,7 +161,7 @@
 
     @CalledByNative
     private void onUpdateScripts(String[] scriptNames, String[] scriptPaths) {
-        List<AutofillAssistantUiDelegate.ScriptHandle> scriptHandles = new ArrayList<>();
+        ArrayList<AutofillAssistantUiDelegate.ScriptHandle> scriptHandles = new ArrayList<>();
         // Note that scriptNames and scriptPaths are one-on-one matched by index.
         for (int i = 0; i < scriptNames.length; i++) {
             scriptHandles.add(
@@ -160,9 +170,23 @@
         mUiDelegate.updateScripts(scriptHandles);
     }
 
+    @CalledByNative
+    private void onChooseAddress() {
+        mUiDelegate.showProfiles(PersonalDataManager.getInstance().getProfilesToSuggest(
+                true /* includeNameInLabel */));
+    }
+
+    @CalledByNative
+    private void onChooseCard() {
+        mUiDelegate.showCards(PersonalDataManager.getInstance().getCreditCardsToSuggest(
+                true /* includeServerCards */));
+    }
+
     // native methods.
     private native long nativeInit(
             WebContents webContents, String[] parameterNames, String[] parameterValues);
     private native void nativeDestroy(long nativeUiControllerAndroid);
     private native void nativeOnScriptSelected(long nativeUiControllerAndroid, String scriptPath);
+    private native void nativeOnAddressSelected(long nativeUiControllerAndroid, String guid);
+    private native void nativeOnCardSelected(long nativeUiControllerAndroid, String guid);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java
index 912ce8d..1927b62 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill_assistant/AutofillAssistantUiDelegate.java
@@ -12,8 +12,10 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
 
-import java.util.List;
+import java.util.ArrayList;
 
 import javax.annotation.Nullable;
 
@@ -24,7 +26,7 @@
     private final View mFullContainer;
     private final View mOverlay;
     private final LinearLayout mBottomBar;
-    private final ViewGroup mScriptsViewContainer;
+    private final ViewGroup mChipsViewContainer;
     private final TextView mStatusMessageView;
 
     /**
@@ -49,6 +51,20 @@
          * @param scriptPath The path for the selected script.
          */
         void onScriptSelected(String scriptPath);
+
+        /**
+         * Called when an address has been selected.
+         *
+         * @param guid The GUID of the selected address.
+         */
+        void onAddressSelected(String guid);
+
+        /**
+         * Called when a credit card has been selected.
+         *
+         * @param guid The GUID of the selected card.
+         */
+        void onCardSelected(String guid);
     }
 
     /**
@@ -113,7 +129,7 @@
                         // TODO(crbug.com/806868): Send feedback.
                     }
                 });
-        mScriptsViewContainer = mBottomBar.findViewById(R.id.carousel);
+        mChipsViewContainer = mBottomBar.findViewById(R.id.carousel);
         mStatusMessageView = mBottomBar.findViewById(R.id.status_message);
 
         // TODO(crbug.com/806868): Listen for contextual search shown so as to hide this UI.
@@ -125,33 +141,43 @@
      * @param message Message to display.
      */
     public void showStatusMessage(@Nullable String message) {
-        if (!mFullContainer.isShown()) mFullContainer.setVisibility(View.VISIBLE);
+        ensureFullContainerIsShown();
 
         mStatusMessageView.setText(message);
     }
 
+    private void ensureFullContainerIsShown() {
+        if (!mFullContainer.isShown()) mFullContainer.setVisibility(View.VISIBLE);
+    }
+
     /**
      * Updates the list of scripts in the bar.
      *
-     * @param scripts List of scripts to show.
+     * @param scriptHandles List of scripts to show.
      */
-    public void updateScripts(List<ScriptHandle> scriptHandles) {
-        mScriptsViewContainer.removeAllViews();
+    public void updateScripts(ArrayList<ScriptHandle> scriptHandles) {
+        mChipsViewContainer.removeAllViews();
 
         if (scriptHandles.isEmpty()) {
             return;
         }
 
-        for (ScriptHandle scriptHandle : scriptHandles) {
-            TextView scriptView = (TextView) (LayoutInflater.from(mActivity).inflate(
-                    R.layout.autofill_assistant_chip, null));
-            scriptView.setText(scriptHandle.getName());
-            scriptView.setOnClickListener(
-                    (unusedView) -> { mClient.onScriptSelected(scriptHandle.getPath()); });
-            mScriptsViewContainer.addView(scriptView);
+        for (int i = 0; i < scriptHandles.size(); i++) {
+            ScriptHandle scriptHandle = scriptHandles.get(i);
+            TextView chipView = createChipView(scriptHandle.getName());
+            chipView.setOnClickListener(
+                    (unusedView) -> mClient.onScriptSelected(scriptHandle.getPath()));
+            mChipsViewContainer.addView(chipView);
         }
 
-        if (!mFullContainer.isShown()) mFullContainer.setVisibility(View.VISIBLE);
+        ensureFullContainerIsShown();
+    }
+
+    private TextView createChipView(String text) {
+        TextView chipView = (TextView) (LayoutInflater.from(mActivity).inflate(
+                R.layout.autofill_assistant_chip, null /* root */));
+        chipView.setText(text);
+        return chipView;
     }
 
     /** Called to show overlay. */
@@ -171,4 +197,47 @@
         mFullContainer.setVisibility(View.GONE);
         mClient.onDismiss();
     }
+
+    /**
+     * Show profiles in the bar.
+     *
+     * @param profiles List of profiles to show.
+     */
+    public void showProfiles(ArrayList<AutofillProfile> profiles) {
+        mChipsViewContainer.removeAllViews();
+
+        if (profiles.isEmpty()) return;
+
+        for (int i = 0; i < profiles.size(); i++) {
+            AutofillProfile profile = profiles.get(i);
+            // TODO(crbug.com/806868): Show more information than the street.
+            TextView chipView = createChipView(profile.getStreetAddress());
+            chipView.setOnClickListener(
+                    (unusedView) -> mClient.onAddressSelected(profile.getGUID()));
+            mChipsViewContainer.addView(chipView);
+        }
+
+        ensureFullContainerIsShown();
+    }
+
+    /**
+     * Show credit cards in the bar.
+     *
+     * @param cards List of cards to show.
+     */
+    public void showCards(ArrayList<CreditCard> cards) {
+        mChipsViewContainer.removeAllViews();
+
+        if (cards.isEmpty()) return;
+
+        for (int i = 0; i < cards.size(); i++) {
+            CreditCard card = cards.get(i);
+            // TODO(crbug.com/806868): Show more information than the card number.
+            TextView chipView = createChipView(card.getObfuscatedNumber());
+            chipView.setOnClickListener((unusedView) -> mClient.onCardSelected(card.getGUID()));
+            mChipsViewContainer.addView(chipView);
+        }
+
+        ensureFullContainerIsShown();
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfo.java
index 308e8d3..648fddf1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadInfo.java
@@ -10,6 +10,7 @@
 import org.chromium.chrome.browser.download.ui.DownloadFilter;
 import org.chromium.components.download.DownloadState;
 import org.chromium.components.offline_items_collection.ContentId;
+import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineItem;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
@@ -56,6 +57,8 @@
     private final Bitmap mIcon;
     @PendingState
     private final int mPendingState;
+    @FailState
+    private final int mFailState;
 
     private DownloadInfo(Builder builder) {
         mUrl = builder.mUrl;
@@ -93,6 +96,7 @@
         mIsParallelDownload = builder.mIsParallelDownload;
         mIcon = builder.mIcon;
         mPendingState = builder.mPendingState;
+        mFailState = builder.mFailState;
     }
 
     public String getUrl() {
@@ -218,6 +222,10 @@
         return mPendingState;
     }
 
+    public @FailState int getFailState() {
+        return mFailState;
+    }
+
     /**
      * Helper method to build a {@link DownloadInfo} from an {@link OfflineItem}.
      * @param item The {@link OfflineItem} to mimic.
@@ -270,6 +278,7 @@
                 .setIsParallelDownload(item.isAccelerated)
                 .setIcon(visuals == null ? null : visuals.icon)
                 .setPendingState(item.pendingState)
+                .setFailState(item.failState)
                 .build();
     }
 
@@ -296,6 +305,7 @@
         offlineItem.mimeType = downloadInfo.getMimeType();
         offlineItem.progress = downloadInfo.getProgress();
         offlineItem.isDangerous = downloadInfo.getIsDangerous();
+        offlineItem.failState = downloadInfo.getFailState();
         switch (downloadInfo.state()) {
             case DownloadState.IN_PROGRESS:
                 offlineItem.state = downloadInfo.isPaused() ? OfflineItemState.PAUSED
@@ -377,6 +387,8 @@
         private Bitmap mIcon;
         @PendingState
         private int mPendingState;
+        @FailState
+        private int mFailState;
 
         public Builder setUrl(String url) {
             mUrl = url;
@@ -528,6 +540,11 @@
             return this;
         }
 
+        public Builder setFailState(@FailState int failState) {
+            mFailState = failState;
+            return this;
+        }
+
         public DownloadInfo build() {
             return new DownloadInfo(this);
         }
@@ -566,7 +583,8 @@
                     .setIsTransient(downloadInfo.getIsTransient())
                     .setIsParallelDownload(downloadInfo.getIsParallelDownload())
                     .setIcon(downloadInfo.getIcon())
-                    .setPendingState(downloadInfo.getPendingState());
+                    .setPendingState(downloadInfo.getPendingState())
+                    .setFailState(downloadInfo.getFailState());
             return builder;
         }
     }
@@ -577,7 +595,7 @@
             boolean isIncognito, int state, int percentCompleted, boolean isPaused,
             boolean hasUserGesture, boolean isResumable, boolean isParallelDownload,
             String originalUrl, String referrerUrl, long timeRemainingInMs, long lastAccessTime,
-            boolean isDangerous) {
+            boolean isDangerous, @FailState int failState) {
         String remappedMimeType = ChromeDownloadDelegate.remapGenericMimeType(
                 mimeType, url, fileName);
 
@@ -605,6 +623,7 @@
                 .setLastAccessTime(lastAccessTime)
                 .setIsDangerous(isDangerous)
                 .setUrl(url)
+                .setFailState(failState)
                 .build();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index f02b4e3..443c652 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -498,7 +498,7 @@
                 break;
             case DownloadStatus.FAILED:
                 // TODO(cmsy): Use correct FailState.
-                mDownloadNotifier.notifyDownloadFailed(info, FailState.CANNOT_DOWNLOAD);
+                mDownloadNotifier.notifyDownloadFailed(info);
                 Log.w(TAG, "Download failed: " + info.getFilePath());
                 onDownloadFailed(item, DownloadManager.ERROR_UNKNOWN);
                 break;
@@ -555,8 +555,10 @@
                             info, result.first, result.second, isSupportedMimeType);
                     broadcastDownloadSuccessful(info);
                 } else {
-                    // TODO(cmsy): Use correct FailState.
-                    mDownloadNotifier.notifyDownloadFailed(info, FailState.CANNOT_DOWNLOAD);
+                    info = DownloadInfo.Builder.fromDownloadInfo(info)
+                                   .setFailState(FailState.CANNOT_DOWNLOAD)
+                                   .build();
+                    mDownloadNotifier.notifyDownloadFailed(info);
                     // TODO(qinmin): get the failure message from native.
                     onDownloadFailed(item, DownloadManager.ERROR_UNKNOWN);
                 }
@@ -1138,10 +1140,10 @@
 
     @CalledByNative
     void onResumptionFailed(String downloadGuid) {
-        // TODO(cmsy): Use correct FailState.
-        mDownloadNotifier.notifyDownloadFailed(
-                new DownloadInfo.Builder().setDownloadGuid(downloadGuid).build(),
-                FailState.CANNOT_DOWNLOAD);
+        mDownloadNotifier.notifyDownloadFailed(new DownloadInfo.Builder()
+                                                       .setDownloadGuid(downloadGuid)
+                                                       .setFailState(FailState.CANNOT_DOWNLOAD)
+                                                       .build());
         removeDownloadProgress(downloadGuid);
         recordDownloadResumption(UmaDownloadResumption.FAILED);
         recordDownloadFinishedUMA(DownloadStatus.FAILED, downloadGuid, 0);
@@ -1632,7 +1634,7 @@
      */
     private boolean isFilePathOnMissingExternalDrive(String filePath, String externalStorageDir,
             ArrayList<DirectoryOption> directoryOptions) {
-        if (filePath.contains(externalStorageDir)) {
+        if (TextUtils.isEmpty(filePath) || filePath.contains(externalStorageDir)) {
             return false;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
index a987c3aa..789dc32 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -59,6 +59,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.util.IntentUtils;
 import org.chromium.components.offline_items_collection.ContentId;
+import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
 import org.chromium.content_public.browser.BrowserStartupController;
@@ -888,7 +889,8 @@
         DownloadSharedPreferenceEntry entry =
                 mDownloadSharedPreferenceHelper.getDownloadSharedPreferenceEntry(id);
         if (!isResumable) {
-            notifyDownloadFailed(id, fileName, isOffTheRecord ? null : icon);
+            notifyDownloadFailed(
+                    id, fileName, isOffTheRecord ? null : icon, FailState.CANNOT_DOWNLOAD);
             return;
         }
         // Download is already paused.
@@ -1012,9 +1014,11 @@
      * @param id       The {@link ContentId} of the download.
      * @param fileName Filename of the download.
      * @param icon     A {@link Bitmap} to be used as the large icon for display.
+     * @param failState Reason of the failure.
      */
     @VisibleForTesting
-    public void notifyDownloadFailed(ContentId id, String fileName, Bitmap icon) {
+    public void notifyDownloadFailed(
+            ContentId id, String fileName, Bitmap icon, @FailState int failState) {
         // If the download is not in history db, fileName could be empty. Get it from
         // SharedPreferences.
         if (TextUtils.isEmpty(fileName)) {
@@ -1025,10 +1029,9 @@
         }
 
         int notificationId = getNotificationId(id);
+        String message = DownloadUtils.getFailStatusString(failState);
         ChromeNotificationBuilder builder =
-                buildNotification(android.R.drawable.stat_sys_download_done, fileName,
-                        ContextUtils.getApplicationContext().getResources().getString(
-                                R.string.download_notification_failed));
+                buildNotification(android.R.drawable.stat_sys_download_done, fileName, message);
         if (icon != null) builder.setLargeIcon(icon);
         builder.setDeleteIntent(buildSummaryIconIntent(notificationId));
         updateNotification(notificationId, builder.build(), id, null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotifier.java
index 56326bf..48081281e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotifier.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.download;
 
 import org.chromium.components.offline_items_collection.ContentId;
-import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.PendingState;
 
 /**
@@ -25,9 +24,8 @@
     /**
      * Add a download failed notification.
      * @param downloadInfo info about the failed download.
-     * @param failState The reason the download failed.
      */
-    void notifyDownloadFailed(DownloadInfo downloadInfo, @FailState int failState);
+    void notifyDownloadFailed(DownloadInfo downloadInfo);
 
     /**
      * Update the download progress notification.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
index dcd4c47..4dcdd495 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -910,21 +910,11 @@
      * @return String representing the current download status.
      */
     public static String getFailStatusString(@FailState int failState) {
+        if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
+                        .isStartupSuccessfullyCompleted()) {
+            return nativeGetFailStateMessage(failState);
+        }
         Context context = ContextUtils.getApplicationContext();
-
-        // TODO(cmsy): Return correct status for failure reasons once strings are finalized.
-        // if (BrowserStartupController.get(LibraryProcessType.PROCESS_BROWSER)
-        //                .isStartupSuccessfullyCompleted()
-        //        && ChromeFeatureList.isEnabled(
-        //                   ChromeFeatureList.OFFLINE_PAGES_DESCRIPTIVE_FAIL_STATUS)) {
-        //    switch (failState) {
-        //        case FailState.CANNOT_DOWNLOAD:
-        //        case FailState.NETWORK_INSTABILITY:
-        //        default:
-        //          return context.getString(R.string.download_notification_failed);
-        //    }
-        // }
-
         return context.getString(R.string.download_notification_failed);
     }
 
@@ -1173,4 +1163,6 @@
         String primaryPath = primaryDir.getAbsolutePath();
         return primaryPath == null ? false : path.contains(primaryPath);
     }
+
+    private static native String nativeGetFailStateMessage(@FailState int failState);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
index 8ac539c..60c350d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
@@ -17,7 +17,6 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.download.DownloadNotificationService.Observer;
 import org.chromium.components.offline_items_collection.ContentId;
-import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.PendingState;
 
 import java.lang.annotation.Retention;
@@ -189,7 +188,7 @@
     }
 
     @Override
-    public void notifyDownloadFailed(DownloadInfo downloadInfo, @FailState int notUsed) {
+    public void notifyDownloadFailed(DownloadInfo downloadInfo) {
         updateDownloadNotification(
                 new PendingNotificationInfo(DownloadNotificationType.FAILURE, downloadInfo), true);
     }
@@ -314,8 +313,8 @@
                 onSuccessNotificationShown(notificationInfo, notificationId);
                 break;
             case DownloadNotificationType.FAILURE:
-                mBoundService.notifyDownloadFailed(
-                        info.getContentId(), info.getFileName(), info.getIcon());
+                mBoundService.notifyDownloadFailed(info.getContentId(), info.getFileName(),
+                        info.getIcon(), info.getFailState());
                 break;
             case DownloadNotificationType.CANCEL:
                 mBoundService.notifyDownloadCanceled(info.getContentId());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java
index b0c7db2..c1406b10 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier2.java
@@ -11,7 +11,6 @@
 import org.chromium.base.ContextUtils;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.components.offline_items_collection.ContentId;
-import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.PendingState;
 
 import java.lang.annotation.Retention;
@@ -75,8 +74,6 @@
         boolean mIsSupportedMimeType;
         boolean mCanDownloadWhileMetered;
         boolean mIsAutoResumable;
-        @FailState
-        int mFailState;
         @PendingState
         int mPendingState;
 
@@ -136,9 +133,10 @@
     }
 
     @Override
-    public void notifyDownloadFailed(DownloadInfo info, @FailState int failState) {
-        getDownloadNotificationService().notifyDownloadFailed(info.getContentId(),
-                info.getFileName(), info.getIcon(), info.isOffTheRecord(), failState);
+    public void notifyDownloadFailed(DownloadInfo info) {
+        NotificationInfo notificationInfo =
+                new NotificationInfo(NotificationType.FAILED, info, NotificationPriority.HIGH);
+        addPendingNotification(notificationInfo);
     }
 
     @Override
@@ -261,7 +259,7 @@
             case NotificationType.FAILED:
                 getDownloadNotificationService().notifyDownloadFailed(info.getContentId(),
                         info.getFileName(), info.getIcon(), info.isOffTheRecord(),
-                        notificationInfo.mFailState);
+                        info.getFailState());
                 break;
             case NotificationType.INTERRUPTED:
                 getDownloadNotificationService().notifyDownloadPaused(info.getContentId(),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/ThumbnailRequestGlue.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/ThumbnailRequestGlue.java
index 1bd48a9a..462e150 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/ThumbnailRequestGlue.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/ThumbnailRequestGlue.java
@@ -71,7 +71,7 @@
     @Override
     public boolean getThumbnail(Callback<Bitmap> callback) {
         return mProvider.getVisualsForItem(mItem.id, (id, visuals) -> {
-            if (visuals == null) {
+            if (visuals == null || visuals.icon == null) {
                 callback.onResult(null);
             } else {
                 callback.onResult(Bitmap.createScaledBitmap(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
index b794adb..5cd286bf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
@@ -34,6 +34,7 @@
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
 import org.chromium.components.offline_items_collection.OfflineItemShareInfo;
+import org.chromium.components.offline_items_collection.OfflineItemState;
 import org.chromium.components.offline_items_collection.VisualsCallback;
 
 import java.io.Closeable;
@@ -245,6 +246,10 @@
         onDeleteItems(CollectionUtil.newArrayList(item));
     }
 
+    /**
+     * Deletes a given list of items. If the items are not completed yet, they would be cancelled.
+     * @param items The list of items to delete.
+     */
     private void onDeleteItems(List<OfflineItem> items) {
         // Calculate the real offline items we are going to remove here.
         final Collection<OfflineItem> itemsToDelete =
@@ -254,7 +259,11 @@
         mDeleteController.canDelete(items, delete -> {
             if (delete) {
                 for (OfflineItem item : itemsToDelete) {
-                    mProvider.removeItem(item);
+                    if (item.state != OfflineItemState.COMPLETE) {
+                        mProvider.cancelDownload(item);
+                    } else {
+                        mProvider.removeItem(item);
+                    }
 
                     // Remove and have a single decision path for cleaning up thumbnails when the
                     // glue layer is no longer needed.
@@ -288,7 +297,7 @@
 
     private Runnable getVisuals(
             OfflineItem item, int iconWidthPx, int iconHeightPx, VisualsCallback callback) {
-        if (!UiUtils.canHaveThumbnails(item)) {
+        if (!UiUtils.canHaveThumbnails(item) || iconWidthPx == 0 || iconHeightPx == 0) {
             mHandler.post(() -> callback.onVisualsAvailable(item.id, null));
             return () -> {};
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java
index dca0e42..efb7742 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java
@@ -107,13 +107,17 @@
             onItemsRemoved(CollectionUtil.newArrayList(oldItem));
             onItemsAdded(CollectionUtil.newArrayList(item));
         } else {
+            int sectionHeaderIndex = -1;
             for (int i = 0; i < mModel.size(); i++) {
                 ListItem listItem = mModel.get(i);
+                if (listItem instanceof SectionHeaderListItem) sectionHeaderIndex = i;
                 if (!(listItem instanceof OfflineItemListItem)) continue;
 
                 OfflineItem offlineListItem = ((OfflineItemListItem) listItem).item;
                 if (item.id.equals(offlineListItem.id)) {
                     mModel.update(i, new OfflineItemListItem(item));
+                    if (oldItem.state != item.state) updateSectionHeader(sectionHeaderIndex, i);
+                    break;
                 }
             }
         }
@@ -121,11 +125,20 @@
         mModel.dispatchLastEvent();
     }
 
+    private void updateSectionHeader(int sectionHeaderIndex, int offlineItemIndex) {
+        if (sectionHeaderIndex < 0) return;
+
+        SectionHeaderListItem sectionHeader =
+                (SectionHeaderListItem) mModel.get(sectionHeaderIndex);
+        OfflineItem offlineItem = ((OfflineItemListItem) mModel.get(offlineItemIndex)).item;
+        sectionHeader.items.set(offlineItemIndex - sectionHeaderIndex - 1, offlineItem);
+        mModel.update(sectionHeaderIndex, sectionHeader);
+    }
+
     // Flattens out the hierarchical data and adds items to the model in the order they should be
     // displayed. Date header, section header, date separator and section separators are added
     // wherever necessary. The existing items in the model are replaced by the new set of items
     // computed.
-    // TODO(shaktisahu): Write a version having no headers for the prefetch tab.
     private void pushItemsToModel() {
         List<ListItem> listItems = new ArrayList<>();
         int dateIndex = 0;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java
index 30e03543..211965b9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java
@@ -28,7 +28,7 @@
 class DateOrderedListView {
     private final DecoratedListItemModel mModel;
 
-    private final int mImageWidthPx;
+    private final int mIdealImageWidthPx;
     private final int mImagePaddingPx;
     private final int mPrefetchVerticalPaddingPx;
     private final int mPrefetchHorizontalPaddingPx;
@@ -66,8 +66,8 @@
             DateOrderedListObserver dateOrderedListObserver) {
         mModel = model;
 
-        mImageWidthPx =
-                context.getResources().getDimensionPixelSize(R.dimen.download_manager_image_width);
+        mIdealImageWidthPx = context.getResources().getDimensionPixelSize(
+                R.dimen.download_manager_ideal_image_width);
         mImagePaddingPx = context.getResources().getDimensionPixelOffset(
                 R.dimen.download_manager_image_padding);
         mPrefetchHorizontalPaddingPx = context.getResources().getDimensionPixelSize(
@@ -116,7 +116,7 @@
             assert getOrientation() == VERTICAL;
 
             int availableWidth = getWidth() - mImagePaddingPx;
-            int columnWidth = mImageWidthPx - mImagePaddingPx;
+            int columnWidth = mIdealImageWidthPx - mImagePaddingPx;
 
             int easyFitSpan = availableWidth / columnWidth;
             double remaining =
@@ -145,6 +145,7 @@
 
             switch (ListUtils.getViewTypeForItem(mModel.get(position))) {
                 case ListUtils.ViewType.IMAGE:
+                case ListUtils.ViewType.IN_PROGRESS_IMAGE:
                     outRect.left = mImagePaddingPx;
                     outRect.right = mImagePaddingPx;
                     outRect.top = mImagePaddingPx;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java
index d0b2d62..4ba2d164 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListUtils.java
@@ -26,7 +26,8 @@
     /** The potential types of list items that could be displayed. */
     @IntDef({ViewType.DATE, ViewType.IN_PROGRESS, ViewType.GENERIC, ViewType.VIDEO, ViewType.IMAGE,
             ViewType.CUSTOM_VIEW, ViewType.PREFETCH, ViewType.SECTION_HEADER,
-            ViewType.SEPARATOR_DATE, ViewType.SEPARATOR_SECTION, ViewType.IN_PROGRESS_VIDEO})
+            ViewType.SEPARATOR_DATE, ViewType.SEPARATOR_SECTION, ViewType.IN_PROGRESS_VIDEO,
+            ViewType.IN_PROGRESS_IMAGE})
     @Retention(RetentionPolicy.SOURCE)
     public @interface ViewType {
         int DATE = 0;
@@ -40,6 +41,7 @@
         int SEPARATOR_DATE = 8;
         int SEPARATOR_SECTION = 9;
         int IN_PROGRESS_VIDEO = 10;
+        int IN_PROGRESS_IMAGE = 11;
     }
 
     /** Converts a given list of {@link ListItem}s to a list of {@link OfflineItem}s. */
@@ -84,7 +86,7 @@
                     case OfflineItemFilter.FILTER_VIDEO:
                         return inProgress ? ViewType.IN_PROGRESS_VIDEO : ViewType.VIDEO;
                     case OfflineItemFilter.FILTER_IMAGE:
-                        return inProgress ? ViewType.IN_PROGRESS : ViewType.IMAGE;
+                        return inProgress ? ViewType.IN_PROGRESS_IMAGE : ViewType.IMAGE;
                     // case OfflineItemFilter.FILTER_PAGE:
                     // case OfflineItemFilter.FILTER_AUDIO:
                     // case OfflineItemFilter.FILTER_OTHER:
@@ -137,6 +139,12 @@
             return spanCount;
         }
 
-        return getViewTypeForItem(item) == ViewType.IMAGE ? 1 : spanCount;
+        switch (getViewTypeForItem(item)) {
+            case ViewType.IMAGE: // Intentional fallthrough.
+            case ViewType.IN_PROGRESS_IMAGE:
+                return 1;
+            default:
+                return spanCount;
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java
index 4c752178..e606cc14 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java
@@ -5,58 +5,50 @@
 package org.chromium.chrome.browser.download.home.list.holder;
 
 import android.content.res.Resources;
-import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
 import android.support.annotation.DrawableRes;
+import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
-import android.support.v4.widget.ImageViewCompat;
 import android.support.v7.content.res.AppCompatResources;
-import android.support.v7.widget.AppCompatImageView;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.browser.download.home.list.ListItem;
 import org.chromium.chrome.browser.download.home.list.UiUtils;
-import org.chromium.chrome.browser.download.home.view.SelectionView;
 import org.chromium.chrome.browser.modelutil.PropertyModel;
 import org.chromium.chrome.download.R;
 import org.chromium.components.offline_items_collection.OfflineItemVisuals;
 
 /** A {@link RecyclerView.ViewHolder} specifically meant to display a generic {@code OfflineItem}.
  */
-public class GenericViewHolder extends ThumbnailAwareViewHolder {
-    private static final int INVALID_ID = -1;
-
+public class GenericViewHolder extends OfflineItemViewHolder {
     private final TextView mTitle;
     private final TextView mCaption;
-    private final AppCompatImageView mThumbnailView;
 
-    private Bitmap mThumbnailBitmap;
-
-    /** The icon to use when there is no thumbnail. */
-    private @DrawableRes int mIconId = INVALID_ID;
+    private @DrawableRes int mGenericIconId;
 
     /** Creates a new {@link GenericViewHolder} instance. */
     public static GenericViewHolder create(ViewGroup parent) {
         View view = LayoutInflater.from(parent.getContext())
                             .inflate(R.layout.download_manager_generic_item, null);
-        int imageSize = parent.getContext().getResources().getDimensionPixelSize(
-                R.dimen.download_manager_generic_thumbnail_size);
-        return new GenericViewHolder(view, imageSize);
+        return new GenericViewHolder(view);
     }
 
-    private GenericViewHolder(View view, int thumbnailSizePx) {
-        super(view, thumbnailSizePx, thumbnailSizePx);
+    private GenericViewHolder(View view) {
+        super(view);
 
-        mTitle = (TextView) itemView.findViewById(R.id.title);
-        mCaption = (TextView) itemView.findViewById(R.id.caption);
-        mThumbnailView = (AppCompatImageView) itemView.findViewById(R.id.thumbnail);
+        mTitle = itemView.findViewById(R.id.title);
+        mCaption = itemView.findViewById(R.id.caption);
+
+        mThumbnail.setForegroundScaleTypeCompat(ImageView.ScaleType.CENTER);
     }
 
-    // ListItemViewHolder implementation.
+    // OfflineItemViewHolder implementation.
     @Override
     public void bind(PropertyModel properties, ListItem item) {
         super.bind(properties, item);
@@ -65,39 +57,43 @@
         mTitle.setText(offlineItem.item.title);
         mCaption.setText(UiUtils.generateGenericCaption(offlineItem.item));
 
-        mIconId = UiUtils.getIconForItem(offlineItem.item);
-        updateThumbnailView();
+        // Build invalid icon.
+        @DrawableRes
+        int iconId = UiUtils.getIconForItem(offlineItem.item);
+        if (iconId != mGenericIconId) {
+            mGenericIconId = iconId;
+
+            Drawable icon = DrawableCompat.wrap(
+                    ApiCompatibilityUtils.getDrawable(itemView.getResources(), mGenericIconId));
+            DrawableCompat.setTintList(icon,
+                    AppCompatResources.getColorStateList(
+                            itemView.getContext(), R.color.dark_mode_tint));
+
+            mThumbnail.setUnavailableDrawable(icon);
+            mThumbnail.setWaitingDrawable(icon);
+        }
+
+        mSelectionView.setVisibility(mSelectionView.isSelected() ? View.VISIBLE : View.INVISIBLE);
+        mThumbnail.setVisibility(mSelectionView.isSelected() ? View.INVISIBLE : View.VISIBLE);
     }
 
     @Override
-    void onVisualsChanged(ImageView view, OfflineItemVisuals visuals) {
-        mThumbnailBitmap = visuals == null ? null : visuals.icon;
-        updateThumbnailView();
-    }
+    protected Drawable onThumbnailRetrieved(OfflineItemVisuals visuals) {
+        Resources resources = itemView.getResources();
+        boolean hasThumbnail = visuals != null && visuals.icon != null;
 
-    private void updateThumbnailView() {
-        Resources resources = itemView.getContext().getResources();
-        SelectionView selectionView = itemView.findViewById(R.id.selection);
-        selectionView.setVisibility(selectionView.isSelected() ? View.VISIBLE : View.GONE);
-        mThumbnailView.setVisibility(selectionView.isSelected() ? View.GONE : View.VISIBLE);
-        if (mThumbnailBitmap != null) {
-            assert !mThumbnailBitmap.isRecycled();
-
-            mThumbnailView.setBackground(null);
-            ImageViewCompat.setImageTintList(mThumbnailView, null);
-
-            RoundedBitmapDrawable drawable =
-                    RoundedBitmapDrawableFactory.create(resources, mThumbnailBitmap);
+        RoundedBitmapDrawable drawable = null;
+        if (hasThumbnail) {
+            drawable = RoundedBitmapDrawableFactory.create(resources, visuals.icon);
             drawable.setCircular(true);
-            mThumbnailView.setImageDrawable(drawable);
-        } else if (mIconId != INVALID_ID) {
-            mThumbnailView.setBackgroundResource(R.drawable.list_item_icon_modern_bg);
-            mThumbnailView.getBackground().setLevel(
+
+            mThumbnail.setBackground(null);
+        } else {
+            mThumbnail.setBackgroundResource(R.drawable.list_item_icon_modern_bg);
+            mThumbnail.getBackground().setLevel(
                     resources.getInteger(R.integer.list_item_level_default));
-            mThumbnailView.setImageResource(mIconId);
-            ImageViewCompat.setImageTintList(mThumbnailView,
-                    AppCompatResources.getColorStateList(
-                            mThumbnailView.getContext(), R.color.dark_mode_tint));
         }
+
+        return drawable;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ImageViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ImageViewHolder.java
index 199eb937d..b35d4443 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ImageViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ImageViewHolder.java
@@ -4,26 +4,16 @@
 
 package org.chromium.chrome.browser.download.home.list.holder;
 
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 
 import org.chromium.chrome.browser.download.home.list.ListItem;
-import org.chromium.chrome.browser.download.home.list.ListProperties;
-import org.chromium.chrome.browser.download.home.list.view.AsyncImageView;
 import org.chromium.chrome.browser.modelutil.PropertyModel;
 import org.chromium.chrome.download.R;
-import org.chromium.components.offline_items_collection.ContentId;
-import org.chromium.components.offline_items_collection.OfflineItem;
 
 /** A {@link RecyclerView.ViewHolder} specifically meant to display an image {@code OfflineItem}. */
-public class ImageViewHolder extends ListItemViewHolder {
-    private final AsyncImageView mThumbnail;
-
-    private ContentId mBoundItemId;
-
+public class ImageViewHolder extends OfflineItemViewHolder {
     public static ImageViewHolder create(ViewGroup parent) {
         View view = LayoutInflater.from(parent.getContext())
                             .inflate(R.layout.download_manager_image_item, null);
@@ -32,30 +22,12 @@
 
     public ImageViewHolder(View view) {
         super(view);
-        mThumbnail = itemView.findViewById(R.id.thumbnail);
     }
 
     // ListItemViewHolder implementation.
     @Override
     public void bind(PropertyModel properties, ListItem item) {
-        OfflineItem offlineItem = ((ListItem.OfflineItemListItem) item).item;
-
-        mThumbnail.setContentDescription(offlineItem.title);
-
-        if (offlineItem.id.equals(mBoundItemId)) return;
-        mBoundItemId = offlineItem.id;
-
-        mThumbnail.setAsyncImageDrawable((consumer, width, height) -> {
-            return properties.get(ListProperties.PROVIDER_VISUALS)
-                    .getVisuals(offlineItem, width, height, (id, visuals) -> {
-                        if (!id.equals(mBoundItemId)) return;
-
-                        Drawable drawable = null;
-                        if (visuals != null && visuals.icon != null) {
-                            drawable = new BitmapDrawable(itemView.getResources(), visuals.icon);
-                        }
-                        consumer.onResult(drawable);
-                    });
-        });
+        super.bind(properties, item);
+        mThumbnail.setContentDescription(((ListItem.OfflineItemListItem) item).item.title);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressImageViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressImageViewHolder.java
new file mode 100644
index 0000000..bf61b14
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressImageViewHolder.java
@@ -0,0 +1,89 @@
+// 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.download.home.list.holder;
+
+import android.support.v7.widget.AppCompatImageButton;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.chromium.chrome.browser.download.DownloadUtils;
+import org.chromium.chrome.browser.download.home.list.ListItem;
+import org.chromium.chrome.browser.download.home.list.ListProperties;
+import org.chromium.chrome.browser.download.home.list.UiUtils;
+import org.chromium.chrome.browser.download.home.list.view.AutoAnimatorDrawable;
+import org.chromium.chrome.browser.download.home.list.view.CircularProgressView;
+import org.chromium.chrome.browser.modelutil.PropertyModel;
+import org.chromium.chrome.download.R;
+import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemState;
+
+/**
+ * A {@link RecyclerView.ViewHolder} specifically meant to display an in-progress video {@code
+ * OfflineItem}.
+ */
+public class InProgressImageViewHolder extends ListItemViewHolder {
+    private final ImageView mPlaceholder;
+    private final TextView mCaption;
+    private final CircularProgressView mActionButton;
+    private final AppCompatImageButton mCancelButton;
+
+    /**
+     * Creates a new {@link InProgressViewHolder} instance.
+     */
+    public static InProgressImageViewHolder create(ViewGroup parent) {
+        View view = LayoutInflater.from(parent.getContext())
+                            .inflate(R.layout.download_manager_in_progress_image_item, null);
+        return new InProgressImageViewHolder(view);
+    }
+
+    /** Constructor. */
+    public InProgressImageViewHolder(View view) {
+        super(view);
+
+        mPlaceholder = view.findViewById(R.id.placeholder);
+        mCaption = view.findViewById(R.id.caption);
+        mActionButton = view.findViewById(R.id.action_button);
+        mCancelButton = view.findViewById(R.id.cancel_button);
+
+        mPlaceholder.setImageDrawable(AutoAnimatorDrawable.wrap(
+                org.chromium.chrome.browser.download.home.list.view.UiUtils.getDrawable(
+                        view.getContext(), R.drawable.async_image_view_waiting)));
+    }
+
+    // ListItemViewHolder implementation.
+    @Override
+    public void bind(PropertyModel properties, ListItem item) {
+        OfflineItem offlineItem = ((ListItem.OfflineItemListItem) item).item;
+
+        mPlaceholder.setContentDescription(offlineItem.title);
+        // TODO(shaktisahu): Create status string for the new specs.
+        mCaption.setText(DownloadUtils.getProgressTextForNotification(offlineItem.progress));
+        mCancelButton.setOnClickListener(
+                v -> properties.get(ListProperties.CALLBACK_CANCEL).onResult(offlineItem));
+
+        UiUtils.setProgressForOfflineItem(mActionButton, offlineItem);
+        mActionButton.setOnClickListener(view -> {
+            switch (offlineItem.state) {
+                case OfflineItemState.IN_PROGRESS: // Intentional fallthrough.
+                case OfflineItemState.PENDING:
+                    properties.get(ListProperties.CALLBACK_PAUSE).onResult(offlineItem);
+                    break;
+                case OfflineItemState.INTERRUPTED: // Intentional fallthrough.
+                case OfflineItemState.PAUSED:
+                    properties.get(ListProperties.CALLBACK_RESUME).onResult(offlineItem);
+                    break;
+                case OfflineItemState.COMPLETE: // Intentional fallthrough.
+                case OfflineItemState.CANCELLED: // Intentional fallthrough.
+                case OfflineItemState.FAILED:
+                    // TODO(883387): Support retrying failed downloads.
+                    properties.get(ListProperties.CALLBACK_RESUME).onResult(offlineItem);
+                    break;
+            }
+        });
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ListItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ListItemViewHolder.java
index 12365a6..f5e41cb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ListItemViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ListItemViewHolder.java
@@ -51,6 +51,8 @@
                 return SeparatorViewHolder.create(parent, false);
             case ListUtils.ViewType.IN_PROGRESS_VIDEO:
                 return InProgressVideoViewHolder.create(parent);
+            case ListUtils.ViewType.IN_PROGRESS_IMAGE:
+                return InProgressImageViewHolder.create(parent);
         }
 
         assert false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/MoreButtonViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/MoreButtonViewHolder.java
deleted file mode 100644
index 45cdd9f3..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/MoreButtonViewHolder.java
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.download.home.list.holder;
-
-import android.support.annotation.CallSuper;
-import android.view.View;
-
-import org.chromium.chrome.browser.download.home.list.ListItem;
-import org.chromium.chrome.browser.download.home.list.ListProperties;
-import org.chromium.chrome.browser.modelutil.PropertyModel;
-import org.chromium.chrome.browser.widget.ListMenuButton;
-import org.chromium.chrome.download.R;
-
-/**
- * Helper {@link RecyclerView.ViewHolder} that handles showing a 3-dot menu with preset actions.
- */
-class MoreButtonViewHolder extends ListItemViewHolder implements ListMenuButton.Delegate {
-    private final ListMenuButton mMore;
-
-    private Runnable mShareCallback;
-    private Runnable mDeleteCallback;
-
-    /**
-     * Creates a new instance of a {@link MoreButtonViewHolder}.
-     */
-    public MoreButtonViewHolder(View view) {
-        super(view);
-        mMore = (ListMenuButton) view.findViewById(R.id.more);
-        if (mMore != null) mMore.setDelegate(this);
-    }
-
-    // ListItemViewHolder implementation.
-    @CallSuper
-    @Override
-    public void bind(PropertyModel properties, ListItem item) {
-        ListItem.OfflineItemListItem offlineItem = (ListItem.OfflineItemListItem) item;
-        mShareCallback =
-                () -> properties.get(ListProperties.CALLBACK_SHARE).onResult(offlineItem.item);
-        mDeleteCallback =
-                () -> properties.get(ListProperties.CALLBACK_REMOVE).onResult(offlineItem.item);
-        if (mMore != null) {
-            mMore.setClickable(!properties.get(ListProperties.SELECTION_MODE_ACTIVE));
-        }
-    }
-
-    // ListMenuButton.Delegate implementation.
-    @Override
-    public ListMenuButton.Item[] getItems() {
-        return new ListMenuButton.Item[] {
-                new ListMenuButton.Item(itemView.getContext(), R.string.share, true),
-                new ListMenuButton.Item(itemView.getContext(), R.string.delete, true)};
-    }
-
-    @Override
-    public void onItemSelected(ListMenuButton.Item item) {
-        if (item.getTextId() == R.string.share) {
-            if (mShareCallback != null) mShareCallback.run();
-        } else if (item.getTextId() == R.string.delete) {
-            if (mDeleteCallback != null) mDeleteCallback.run();
-        }
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/OfflineItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/OfflineItemViewHolder.java
new file mode 100644
index 0000000..861d1c5
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/OfflineItemViewHolder.java
@@ -0,0 +1,136 @@
+// 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.download.home.list.holder;
+
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.CallSuper;
+import android.view.View;
+
+import org.chromium.chrome.browser.download.home.list.ListItem;
+import org.chromium.chrome.browser.download.home.list.ListProperties;
+import org.chromium.chrome.browser.download.home.list.view.AsyncImageView;
+import org.chromium.chrome.browser.download.home.view.SelectionView;
+import org.chromium.chrome.browser.modelutil.PropertyModel;
+import org.chromium.chrome.browser.widget.ListMenuButton;
+import org.chromium.chrome.download.R;
+import org.chromium.components.offline_items_collection.OfflineItem;
+import org.chromium.components.offline_items_collection.OfflineItemVisuals;
+
+/**
+ * Helper that supports all typical actions for OfflineItems.
+ */
+class OfflineItemViewHolder extends ListItemViewHolder implements ListMenuButton.Delegate {
+    /** The {@link View} that visually represents the selected state of this list item. */
+    protected final SelectionView mSelectionView;
+
+    /** The {@link View} that visually represents the thumbnail of this list item. */
+    protected final AsyncImageView mThumbnail;
+
+    private final ListMenuButton mMore;
+
+    // Persisted 'More' button properties.
+    private Runnable mShareCallback;
+    private Runnable mDeleteCallback;
+
+    /**
+     * Creates a new instance of a {@link MoreButtonViewHolder}.
+     */
+    public OfflineItemViewHolder(View view) {
+        super(view);
+        mSelectionView = itemView.findViewById(R.id.selection);
+        mMore = itemView.findViewById(R.id.more);
+        mThumbnail = itemView.findViewById(R.id.thumbnail);
+
+        if (mMore != null) mMore.setDelegate(this);
+    }
+
+    // ListItemViewHolder implementation.
+    @CallSuper
+    @Override
+    public void bind(PropertyModel properties, ListItem item) {
+        OfflineItem offlineItem = ((ListItem.OfflineItemListItem) item).item;
+
+        // Push 'interaction' state.
+        itemView.setOnClickListener(v -> {
+            if (mSelectionView != null && mSelectionView.isInSelectionMode()) {
+                properties.get(ListProperties.CALLBACK_SELECTION).onResult(item);
+            } else {
+                properties.get(ListProperties.CALLBACK_OPEN).onResult(offlineItem);
+            }
+        });
+
+        itemView.setOnLongClickListener(v -> {
+            properties.get(ListProperties.CALLBACK_SELECTION).onResult(item);
+            return true;
+        });
+
+        // Push 'More' state.
+        if (mMore != null) {
+            mShareCallback =
+                    () -> properties.get(ListProperties.CALLBACK_SHARE).onResult(offlineItem);
+            mDeleteCallback =
+                    () -> properties.get(ListProperties.CALLBACK_REMOVE).onResult(offlineItem);
+
+            mMore.setClickable(!properties.get(ListProperties.SELECTION_MODE_ACTIVE));
+        }
+
+        // Push 'selection' state.
+        if (shouldPushSelection(properties, item)) {
+            mSelectionView.setSelectionState(item.selected,
+                    properties.get(ListProperties.SELECTION_MODE_ACTIVE),
+                    item.showSelectedAnimation);
+        }
+
+        // Push 'thumbnail' state.
+        if (mThumbnail != null) {
+            mThumbnail.setAsyncImageDrawable((consumer, width, height) -> {
+                return properties.get(ListProperties.PROVIDER_VISUALS)
+                        .getVisuals(offlineItem, width, height, (id, visuals) -> {
+                            consumer.onResult(onThumbnailRetrieved(visuals));
+                        });
+            }, offlineItem.id);
+        }
+    }
+
+    /**
+     * Called when a {@link OfflineItemVisuals} are retrieved and are used to build the
+     * {@link Drawable} to use for the thumbnail {@link View}.  Can be overridden by subclasses who
+     * want to do either build a custom {@link Drawable} here (like a circular bitmap).  By default
+     * this builds a simple {@link BitmapDrawable} around {@code visuals.icon}.
+     *
+     * @param visuals The {@link OfflineItemVisuals} from the async request.
+     * @return        A {@link Drawable} to use for the thumbnail.
+     */
+    protected Drawable onThumbnailRetrieved(OfflineItemVisuals visuals) {
+        if (visuals == null || visuals.icon == null) return null;
+        return new BitmapDrawable(itemView.getResources(), visuals.icon);
+    }
+
+    // ListMenuButton.Delegate implementation.
+    @Override
+    public ListMenuButton.Item[] getItems() {
+        return new ListMenuButton.Item[] {
+                new ListMenuButton.Item(itemView.getContext(), R.string.share, true),
+                new ListMenuButton.Item(itemView.getContext(), R.string.delete, true)};
+    }
+
+    @Override
+    public void onItemSelected(ListMenuButton.Item item) {
+        if (item.getTextId() == R.string.share) {
+            if (mShareCallback != null) mShareCallback.run();
+        } else if (item.getTextId() == R.string.delete) {
+            if (mDeleteCallback != null) mDeleteCallback.run();
+        }
+    }
+
+    private boolean shouldPushSelection(PropertyModel properties, ListItem item) {
+        if (mSelectionView == null) return false;
+
+        return mSelectionView.isSelected() != item.selected
+                || mSelectionView.isInSelectionMode()
+                != properties.get(ListProperties.SELECTION_MODE_ACTIVE);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/PrefetchViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/PrefetchViewHolder.java
index 71e1c89..2ae68877 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/PrefetchViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/PrefetchViewHolder.java
@@ -7,19 +7,17 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.ImageView;
 import android.widget.TextView;
 
 import org.chromium.chrome.browser.download.home.list.ListItem;
 import org.chromium.chrome.browser.download.home.list.UiUtils;
 import org.chromium.chrome.browser.modelutil.PropertyModel;
 import org.chromium.chrome.download.R;
-import org.chromium.components.offline_items_collection.OfflineItemVisuals;
 
 /**
  * A {@link RecyclerView.ViewHolder} specifically meant to display a prefetch item.
  */
-public class PrefetchViewHolder extends ThumbnailAwareViewHolder {
+public class PrefetchViewHolder extends OfflineItemViewHolder {
     private final TextView mTitle;
     private final TextView mCaption;
     private final TextView mTimestamp;
@@ -30,13 +28,11 @@
     public static PrefetchViewHolder create(ViewGroup parent) {
         View view = LayoutInflater.from(parent.getContext())
                             .inflate(R.layout.download_manager_prefetch_item, null);
-        int imageSize = parent.getContext().getResources().getDimensionPixelSize(
-                R.dimen.download_manager_prefetch_thumbnail_size);
-        return new PrefetchViewHolder(view, imageSize);
+        return new PrefetchViewHolder(view);
     }
 
-    private PrefetchViewHolder(View view, int thumbnailSizePx) {
-        super(view, thumbnailSizePx, thumbnailSizePx);
+    private PrefetchViewHolder(View view) {
+        super(view);
         mTitle = (TextView) itemView.findViewById(R.id.title);
         mCaption = (TextView) itemView.findViewById(R.id.caption);
         mTimestamp = (TextView) itemView.findViewById(R.id.timestamp);
@@ -52,9 +48,4 @@
         mCaption.setText(UiUtils.generatePrefetchCaption(offlineItem.item));
         mTimestamp.setText(UiUtils.generatePrefetchTimestamp(offlineItem.date));
     }
-
-    @Override
-    void onVisualsChanged(ImageView view, OfflineItemVisuals visuals) {
-        view.setImageBitmap(visuals == null ? null : visuals.icon);
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java
index 2c90e23..e363a23 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java
@@ -12,12 +12,19 @@
 import android.widget.TextView;
 
 import org.chromium.chrome.browser.download.home.list.ListItem;
+import org.chromium.chrome.browser.download.home.list.ListItem.SectionHeaderListItem;
 import org.chromium.chrome.browser.download.home.list.ListProperties;
 import org.chromium.chrome.browser.download.home.list.ListUtils;
 import org.chromium.chrome.browser.modelutil.PropertyModel;
 import org.chromium.chrome.browser.widget.ListMenuButton;
 import org.chromium.chrome.download.R;
+import org.chromium.components.offline_items_collection.OfflineItem;
 import org.chromium.components.offline_items_collection.OfflineItemFilter;
+import org.chromium.components.offline_items_collection.OfflineItemState;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 
 /**
  * A {@link ViewHolder} specifically meant to display a section header.
@@ -32,7 +39,8 @@
     private Runnable mDeleteAllCallback;
     private Runnable mSelectCallback;
 
-    private boolean mListHasMultipleItems;
+    private boolean mHasMultipleItems;
+    private boolean mCanSelectItems;
 
     /** Create a new {@link SectionTitleViewHolder} instance. */
     public static SectionTitleViewHolder create(ViewGroup parent) {
@@ -51,7 +59,7 @@
     // ListItemViewHolder implementation.
     @Override
     public void bind(PropertyModel properties, ListItem item) {
-        ListItem.SectionHeaderListItem sectionItem = (ListItem.SectionHeaderListItem) item;
+        SectionHeaderListItem sectionItem = (SectionHeaderListItem) item;
         mTitle.setText(ListUtils.getTextForSection(sectionItem.filter));
 
         boolean isPhoto = sectionItem.filter == OfflineItemFilter.FILTER_IMAGE;
@@ -74,7 +82,8 @@
 
         if (mMore != null) mMore.setVisibility(isPhoto ? View.VISIBLE : View.GONE);
 
-        mListHasMultipleItems = sectionItem.items.size() > 1;
+        mHasMultipleItems = sectionItem.items.size() > 1;
+        mCanSelectItems = !getCompletedItems(sectionItem.items).isEmpty();
 
         if (isPhoto && mMore != null) {
             assert sectionItem.items.size() > 0;
@@ -87,7 +96,7 @@
 
             mShareAllCallback = ()
                     -> properties.get(ListProperties.CALLBACK_SHARE_ALL)
-                               .onResult(sectionItem.items);
+                               .onResult(getCompletedItems(sectionItem.items));
             mDeleteAllCallback = ()
                     -> properties.get(ListProperties.CALLBACK_REMOVE_ALL)
                                .onResult(sectionItem.items);
@@ -101,14 +110,14 @@
     @Override
     public ListMenuButton.Item[] getItems() {
         Context context = itemView.getContext();
-        if (mListHasMultipleItems) {
+        if (mHasMultipleItems) {
             return new ListMenuButton.Item[] {
-                    new ListMenuButton.Item(context, R.string.select, true),
-                    new ListMenuButton.Item(context, R.string.share_group, true),
+                    new ListMenuButton.Item(context, R.string.select, mCanSelectItems),
+                    new ListMenuButton.Item(context, R.string.share_group, mCanSelectItems),
                     new ListMenuButton.Item(context, R.string.delete_group, true)};
         } else {
             return new ListMenuButton.Item[] {
-                    new ListMenuButton.Item(context, R.string.share, true),
+                    new ListMenuButton.Item(context, R.string.share, mCanSelectItems),
                     new ListMenuButton.Item(context, R.string.delete, true)};
         }
     }
@@ -127,4 +136,14 @@
             mDeleteAllCallback.run();
         }
     }
+
+    private static List<OfflineItem> getCompletedItems(Collection<OfflineItem> items) {
+        List<OfflineItem> completedItems = new ArrayList<>();
+        for (OfflineItem item : items) {
+            if (item.state != OfflineItemState.COMPLETE) continue;
+            completedItems.add(item);
+        }
+
+        return completedItems;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ThumbnailAwareViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ThumbnailAwareViewHolder.java
deleted file mode 100644
index 57e0db7..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ThumbnailAwareViewHolder.java
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.download.home.list.holder;
-
-import android.support.annotation.CallSuper;
-import android.support.annotation.Nullable;
-import android.view.View;
-import android.widget.ImageView;
-
-import org.chromium.chrome.browser.download.home.list.ListItem;
-import org.chromium.chrome.browser.download.home.list.ListProperties;
-import org.chromium.chrome.browser.download.home.view.SelectionView;
-import org.chromium.chrome.browser.modelutil.PropertyModel;
-import org.chromium.chrome.download.R;
-import org.chromium.components.offline_items_collection.ContentId;
-import org.chromium.components.offline_items_collection.OfflineItem;
-import org.chromium.components.offline_items_collection.OfflineItemVisuals;
-import org.chromium.components.offline_items_collection.VisualsCallback;
-
-/**
- * Helper {@link RecyclerView.ViewHolder} that handles querying for thumbnails if necessary.
- */
-abstract class ThumbnailAwareViewHolder extends MoreButtonViewHolder implements VisualsCallback {
-    private final ImageView mThumbnail;
-    private final SelectionView mSelectionView;
-
-    /**
-     * The {@link ContentId} of the associated thumbnail/request if any.
-     */
-    private @Nullable ContentId mId;
-
-    /**
-     * A {@link Runnable} to cancel an outstanding thumbnail request if any.
-     */
-    private @Nullable Runnable mCancellable;
-
-    /**
-     * Whether or not a request is outstanding to support synchronous responses.
-     */
-    private boolean mIsRequesting;
-
-    /**
-     * The ideal width of the queried thumbnail.
-     */
-    private int mWidthPx;
-
-    /**
-     * The ideal height of the queried thumbnail.
-     */
-    private int mHeightPx;
-
-    /**
-     * Creates a new instance of a {@link ThumbnailAwareViewHolder}.
-     * @param view              The root {@link View} for this holder.
-     * @param thumbnailWidthPx  The desired width of the thumbnail that will be retrieved.
-     * @param thumbnailHeightPx The desired height of the thumbnail that will be retrieved.
-     */
-    public ThumbnailAwareViewHolder(View view, int thumbnailWidthPx, int thumbnailHeightPx) {
-        super(view);
-
-        mThumbnail = (ImageView) view.findViewById(R.id.thumbnail);
-        mSelectionView = itemView.findViewById(R.id.selection);
-        mWidthPx = thumbnailWidthPx;
-        mHeightPx = thumbnailHeightPx;
-    }
-
-    // MoreButtonViewHolder implementation.
-    @Override
-    @CallSuper
-    public void bind(PropertyModel properties, ListItem item) {
-        super.bind(properties, item);
-        // If we have no thumbnail to show just return early.
-        if (mThumbnail == null) return;
-
-        OfflineItem offlineItem = ((ListItem.OfflineItemListItem) item).item;
-
-        // If we're rebinding the same item, ignore the bind.
-        if (offlineItem.id.equals(mId) && !selectionStateHasChanged(properties, item)) {
-            return;
-        }
-
-        if (mSelectionView != null) {
-            mSelectionView.setSelectionState(item.selected,
-                    properties.get(ListProperties.SELECTION_MODE_ACTIVE),
-                    item.showSelectedAnimation);
-        }
-
-        itemView.setOnLongClickListener(v -> {
-            properties.get(ListProperties.CALLBACK_SELECTION).onResult(item);
-            return true;
-        });
-
-        itemView.setOnClickListener(v -> {
-            if (mSelectionView != null && mSelectionView.isInSelectionMode()) {
-                properties.get(ListProperties.CALLBACK_SELECTION).onResult(item);
-            } else {
-                properties.get(ListProperties.CALLBACK_OPEN).onResult(offlineItem);
-            }
-        });
-
-        // Clear any associated bitmap from the thumbnail.
-        if (mId != null) onVisualsChanged(mThumbnail, null);
-
-        // Show the loading animation if we are in loading state.
-        showLoadingView(mThumbnail);
-
-        // Clear out any outstanding thumbnail request.
-        if (mCancellable != null) mCancellable.run();
-
-        // Start the new request.
-        mId = offlineItem.id;
-        mCancellable = properties.get(ListProperties.PROVIDER_VISUALS)
-                               .getVisuals(offlineItem, mWidthPx, mHeightPx, this);
-
-        // Make sure to update our state properly if we got a synchronous response.
-        if (!mIsRequesting) mCancellable = null;
-    }
-
-    private boolean selectionStateHasChanged(PropertyModel properties, ListItem item) {
-        if (mSelectionView == null) return false;
-
-        return mSelectionView.isSelected() != item.selected
-                || mSelectionView.isInSelectionMode()
-                != properties.get(ListProperties.SELECTION_MODE_ACTIVE);
-    }
-
-    // VisualsCallback implementation.
-    @Override
-    public void onVisualsAvailable(ContentId id, OfflineItemVisuals visuals) {
-        // Quit early if the request is not for our currently bound item.
-        if (!id.equals(mId)) return;
-
-        // Clear out the request state.
-        mCancellable = null;
-        mIsRequesting = false;
-
-        // Hide the loading view.
-        hideLoadingView();
-
-        // Notify of the new visuals (if any).
-        onVisualsChanged(mThumbnail, visuals);
-    }
-
-    /**
-     * Show UI to indicate that thumbnail loading in progress.
-     * @param view The view that should show the loading image.
-     */
-    protected void showLoadingView(ImageView view) {}
-
-    /** Hide the loading view. */
-    protected void hideLoadingView() {}
-
-    /**
-     * Called when the contents of the thumbnail should be changed to due an event (either this
-     * {@link RecyclerView.ViewHolder} being rebound to another {@link ListItem} or a thumbnail
-     * query returning results.
-     * @param view    The {@link ImageView} that the thumbnail should be set on.
-     * @param visuals The {@link OfflineItemVisuals} that were returned by the backend if any.
-     */
-    abstract void onVisualsChanged(ImageView view, @Nullable OfflineItemVisuals visuals);
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/VideoViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/VideoViewHolder.java
index 591e4ab..a1511fd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/VideoViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/VideoViewHolder.java
@@ -4,31 +4,23 @@
 
 package org.chromium.chrome.browser.download.home.list.holder;
 
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
 import org.chromium.chrome.browser.download.home.list.ListItem;
-import org.chromium.chrome.browser.download.home.list.ListProperties;
 import org.chromium.chrome.browser.download.home.list.UiUtils;
-import org.chromium.chrome.browser.download.home.list.view.AsyncImageView;
 import org.chromium.chrome.browser.modelutil.PropertyModel;
 import org.chromium.chrome.download.R;
-import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.OfflineItem;
 
 /**
  * A {@link RecyclerView.ViewHolder} specifically meant to display a video {@code OfflineItem}.
  */
-public class VideoViewHolder extends MoreButtonViewHolder {
+public class VideoViewHolder extends OfflineItemViewHolder {
     private final TextView mTitle;
     private final TextView mCaption;
-    private final AsyncImageView mThumbnail;
-
-    private ContentId mBoundItemId;
 
     /**
      * Creates a new {@link VideoViewHolder} instance.
@@ -45,34 +37,16 @@
 
         mTitle = itemView.findViewById(R.id.title);
         mCaption = itemView.findViewById(R.id.caption);
-        mThumbnail = itemView.findViewById(R.id.thumbnail);
     }
 
     // MoreButtonViewHolder implementation.
     @Override
     public void bind(PropertyModel properties, ListItem item) {
         super.bind(properties, item);
-
         OfflineItem offlineItem = ((ListItem.OfflineItemListItem) item).item;
 
         mTitle.setText(offlineItem.title);
         mCaption.setText(UiUtils.generateGenericCaption(offlineItem));
         mThumbnail.setContentDescription(offlineItem.title);
-
-        if (offlineItem.id.equals(mBoundItemId)) return;
-        mBoundItemId = offlineItem.id;
-
-        mThumbnail.setAsyncImageDrawable((consumer, width, height) -> {
-            return properties.get(ListProperties.PROVIDER_VISUALS)
-                    .getVisuals(offlineItem, width, height, (id, visuals) -> {
-                        if (!id.equals(mBoundItemId)) return;
-
-                        Drawable drawable = null;
-                        if (visuals != null && visuals.icon != null) {
-                            drawable = new BitmapDrawable(itemView.getResources(), visuals.icon);
-                        }
-                        consumer.onResult(drawable);
-                    });
-        });
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AspectRatioFrameLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AspectRatioFrameLayout.java
new file mode 100644
index 0000000..f7b85ae
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AspectRatioFrameLayout.java
@@ -0,0 +1,162 @@
+// 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.download.home.list.view;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import org.chromium.chrome.download.R;
+
+/**
+ * Helper FrameLayout that knows how to make children fit certain aspect ratios.
+ * TODO(dtrainor): Remove this once we get proper support for constraint layout.
+ *
+ * Below is an example usage to make an ImageView a square based on the width.  Note that you do not
+ * need to set both layout_width and layout_height if setting layout_aspectRatio.
+ *
+ * <org.chromium.chrome.browser.download.home.list.view.AspectRatioFrameLayout
+ *     xmlns:android="http://schemas.android.com/apk/res/android"
+ *     xmlns:app="http://schemas.android.com/apk/res-auto"
+ *     android:layout_width="match_parent"
+ *     android:layout_height="wrap_content">
+ *     <ImageView
+ *         android:layout_width="match_parent"
+ *         app:layout_aspectRatio="100%" />
+ * </org.chromium.chrome.browser.download.home.list.view.AspectRatioFrameLayout>
+ */
+public class AspectRatioFrameLayout extends FrameLayout {
+    /** Creates an instance of {@link AspectRatioFrameLayout}. */
+    public AspectRatioFrameLayout(Context context) {
+        this(context, null);
+    }
+
+    /** Creates an instance of {@link AspectRatioFrameLayout}. */
+    public AspectRatioFrameLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    /** Creates an instance of {@link AspectRatioFrameLayout}. */
+    public AspectRatioFrameLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    // FrameLayout implementation.
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    @SuppressWarnings("DrawAllocation")
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int width =
+                View.MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
+        int height =
+                View.MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
+
+        for (int i = 0; i < getChildCount(); i++) {
+            View view = getChildAt(i);
+
+            if (!(view.getLayoutParams() instanceof LayoutParams)) continue;
+            LayoutParams params = (LayoutParams) view.getLayoutParams();
+
+            params.mRestorableWidth = params.width;
+            params.mRestorableHeight = params.height;
+
+            float aspectRatio = params.aspectRatio;
+            if (aspectRatio <= 0.f) continue;
+
+            boolean widthMovable = params.mOverrodeWidth || params.mRestorableWidth == 0;
+            boolean heightMovable = params.mOverrodeHeight || params.mRestorableHeight == 0;
+
+            if (widthMovable) {
+                int childHeight =
+                        params.height == LayoutParams.MATCH_PARENT ? height : params.height;
+                params.width = Math.round(childHeight * aspectRatio);
+                params.mOverrodeWidth = true;
+            }
+            if (heightMovable) {
+                int childWidth = params.width == LayoutParams.MATCH_PARENT ? width : params.width;
+                params.height = Math.round(childWidth / aspectRatio);
+                params.mOverrodeHeight = true;
+            }
+        }
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+
+        for (int i = 0; i < getChildCount(); i++) {
+            View view = getChildAt(i);
+
+            if (!(view.getLayoutParams() instanceof LayoutParams)) continue;
+            LayoutParams params = (LayoutParams) view.getLayoutParams();
+            if (params.mOverrodeWidth) params.width = params.mRestorableWidth;
+            if (params.mOverrodeHeight) params.height = params.mRestorableHeight;
+            params.mOverrodeWidth = false;
+            params.mOverrodeHeight = false;
+        }
+    }
+
+    /**
+     * A set of layout parameters for {@link AspectRatioFrameLayout}.
+     */
+    public static class LayoutParams extends FrameLayout.LayoutParams {
+        /** The aspect ratio to use and enforce. */
+        public float aspectRatio;
+
+        // Restorable parameters.
+        private boolean mOverrodeWidth;
+        private boolean mOverrodeHeight;
+        private int mRestorableWidth;
+        private int mRestorableHeight;
+
+        public LayoutParams(Context context, AttributeSet attrs) {
+            super(context, attrs);
+
+            TypedArray array = context.obtainStyledAttributes(
+                    attrs, R.styleable.AspectRatioFrameLayout_Layout);
+            aspectRatio = array.getFraction(
+                    R.styleable.AspectRatioFrameLayout_Layout_layout_aspectRatio, 1, 1, 0.f);
+            array.recycle();
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(FrameLayout.LayoutParams source) {
+            super((MarginLayoutParams) source);
+            gravity = source.gravity;
+        }
+
+        @Override
+        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
+            // Do not throw errors if width or height aren't supplied.
+            width = a.getLayoutDimension(widthAttr, 0);
+            height = a.getLayoutDimension(heightAttr, 0);
+        }
+    }
+}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AsyncImageView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AsyncImageView.java
index 8267d1db..9a72102 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AsyncImageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/AsyncImageView.java
@@ -7,6 +7,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.support.annotation.Nullable;
 import android.util.AttributeSet;
 
 import org.chromium.base.Callback;
@@ -36,14 +37,16 @@
         Runnable get(Callback<Drawable> consumer, int widthPx, int heightPx);
     }
 
-    private final Drawable mUnavailableDrawable;
-    private final Drawable mWaitingDrawable;
+    private Drawable mUnavailableDrawable;
+    private Drawable mWaitingDrawable;
 
     private Factory mFactory;
 
     private Runnable mCancelable;
     private boolean mWaitingForResponse;
 
+    private @Nullable Object mIdentifier;
+
     /** Creates an {@link AsyncImageDrawable instance. */
     public AsyncImageView(Context context) {
         this(context, null, 0);
@@ -74,9 +77,16 @@
      * Starts loading a {@link Drawable} from {@code factory}.  This will automatically clear out
      * any outstanding request state and start a new one.
      *
-     * @param factory The {@link Factory} to use that will provide the {@link Drawable}.
+     * @param factory    The {@link Factory} to use that will provide the {@link Drawable}.
+     * @param identifier An identification for this particular request. Subsequent calls with the
+     *                   same {@link Object} will be ignored until either {@code null} or a
+     *                   different {@link Object} are passed in.  This lets us ignore redundant
+     *                   calls.
      */
-    public void setAsyncImageDrawable(Factory factory) {
+    public void setAsyncImageDrawable(Factory factory, @Nullable Object identifier) {
+        if (mIdentifier != null && identifier != null && mIdentifier.equals(identifier)) return;
+        mIdentifier = identifier;
+
         // This will clear out any outstanding request.
         setImageDrawable(null);
         setForegroundDrawableCompat(mWaitingDrawable);
@@ -85,6 +95,26 @@
         retrieveDrawableIfNeeded();
     }
 
+    /**
+     * @param unavailableDrawable Sets the {@link Drawable} to use when there is no thumbnail
+     *                            available.
+     */
+    public void setUnavailableDrawable(Drawable unavailableDrawable) {
+        boolean showUnavailable =
+                getForegroundDrawableCompat() == mUnavailableDrawable && !mWaitingForResponse;
+        mUnavailableDrawable = AutoAnimatorDrawable.wrap(unavailableDrawable);
+        if (showUnavailable) setForegroundDrawableCompat(mUnavailableDrawable);
+    }
+
+    /**
+     * @param waitingDrawable Sets the {@link Drawable} to use when waiting for an outstanding
+     *                        asynchronous thumbnail request.
+     */
+    public void setWaitingDrawable(Drawable waitingDrawable) {
+        mWaitingDrawable = AutoAnimatorDrawable.wrap(waitingDrawable);
+        if (mWaitingForResponse) setForegroundDrawableCompat(mWaitingDrawable);
+    }
+
     // RoundedCornerImageView implementation.
     @Override
     public void setImageDrawable(Drawable drawable) {
@@ -104,7 +134,12 @@
         retrieveDrawableIfNeeded();
     }
 
-    private void setAsyncImageDrawableResponse(Drawable drawable) {
+    private void setAsyncImageDrawableResponse(Drawable drawable, Object identifier) {
+        // If we ended up swapping out the identifier and somehow this request didn't cancel ignore
+        // the response.  This does a direct == comparison instead of .equals() because any new
+        // request should have canceled this one (we'll leave null alone though).
+        if (mIdentifier != identifier) return;
+
         mCancelable = null;
         mWaitingForResponse = false;
         setForegroundDrawableCompat(drawable == null ? mUnavailableDrawable : null);
@@ -129,8 +164,11 @@
         if (mFactory != null) {
             // Start to retrieve the drawable.
             mWaitingForResponse = true;
-            mCancelable =
-                    mFactory.get(this ::setAsyncImageDrawableResponse, getWidth(), getHeight());
+
+            Object localIdentifier = mIdentifier;
+            mCancelable = mFactory.get(d
+                    -> setAsyncImageDrawableResponse(d, localIdentifier),
+                    getWidth(), getHeight());
 
             // If setAsyncImageDrawableResponse is called synchronously, clear mCancelable.
             if (!mWaitingForResponse) mCancelable = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/CircularProgressView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/CircularProgressView.java
index cdbd65d..37db344 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/CircularProgressView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/CircularProgressView.java
@@ -103,8 +103,10 @@
         if (progress == INDETERMINATE) {
             mForegroundHelper.setDrawable(mIndeterminateProgress);
         } else {
-            progress = MathUtils.clamp(progress, 0, 100);
-            mDeterminateProgress.setLevel(progress * MAX_LEVEL / 100);
+            if (mDeterminateProgress != null) {
+                progress = MathUtils.clamp(progress, 0, 100);
+                mDeterminateProgress.setLevel(progress * MAX_LEVEL / 100);
+            }
             mForegroundHelper.setDrawable(mDeterminateProgress);
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundDrawableCompat.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundDrawableCompat.java
index ba6487f3..3f83fbaf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundDrawableCompat.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundDrawableCompat.java
@@ -80,8 +80,6 @@
     private boolean mOnBoundsChanged;
     private Drawable mDrawable;
 
-    // TODO(dtrainor): Add support for more scale types.
-    // Right now the only two supported types are FIT_* tyes.
     private ImageView.ScaleType mScaleType = ImageView.ScaleType.FIT_CENTER;
 
     /**
@@ -137,6 +135,10 @@
 
     /**
      * Determines how the foreground {@code Drawable} will be drawn in front of the {@link View}.
+     * Right now the only supported types are FIT_* types and the CENTER type.
+     *
+     * TODO(dtrainor): Add support for more scale types.
+     *
      * @param type The type of scale to apply to the {@Drawable} (see {@link ImageView.ScaleType}).
      */
     public void setScaleType(ImageView.ScaleType type) {
@@ -242,6 +244,10 @@
         } else if (mScaleType == ImageView.ScaleType.FIT_END) {
             mDrawMatrix.setRectToRect(mTempSrc, mTempDst, ScaleToFit.END);
             mDrawable.setBounds(0, 0, drawableWidth, drawableHeight);
+        } else if (mScaleType == ImageView.ScaleType.CENTER) {
+            mDrawMatrix.setTranslate(Math.round((viewWidth - drawableWidth) * 0.5f),
+                    Math.round((viewHeight - drawableHeight) * 0.5f));
+            mDrawable.setBounds(0, 0, drawableWidth, drawableHeight);
         } else {
             mDrawable.setBounds(0, 0, viewWidth, viewHeight);
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundRoundedCornerImageView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundRoundedCornerImageView.java
index 13b09d6..036dc4df2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundRoundedCornerImageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundRoundedCornerImageView.java
@@ -10,6 +10,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
+import android.widget.ImageView;
 
 import org.chromium.chrome.download.R;
 import org.chromium.ui.widget.RoundedCornerImageView;
@@ -50,6 +51,19 @@
         mForegroundHelper.setDrawable(drawable);
     }
 
+    /** @return The current foreground {@link Drawable}. */
+    public Drawable getForegroundDrawableCompat() {
+        return mForegroundHelper.getDrawable();
+    }
+
+    /**
+     * @param scaleType Sets the {@link ImageView.ScaleType} to use for the foreground
+     *                  {@link Drawable}.
+     */
+    public void setForegroundScaleTypeCompat(ImageView.ScaleType scaleType) {
+        mForegroundHelper.setScaleType(scaleType);
+    }
+
     // RoundedCornerImageView implementation.
     @Override
     public void draw(Canvas canvas) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/SquareAsyncImageView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/SquareAsyncImageView.java
deleted file mode 100644
index 49595165..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/view/SquareAsyncImageView.java
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.download.home.list.view;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-/**
- * Helper {@link AsyncImageView} that will force the dimensions of the view to be equal.
- */
-public class SquareAsyncImageView extends AsyncImageView {
-    /** Creates an instance of {@link SquareAsyncImageView}. */
-    public SquareAsyncImageView(Context context) {
-        this(context, null, 0);
-    }
-
-    /** Creates an instance of {@link SquareAsyncImageView}. */
-    public SquareAsyncImageView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    /** Creates an instance of {@link SquareAsyncImageView}. */
-    public SquareAsyncImageView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
-    }
-
-    // AsyncImageView implementation.
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
-        int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
-
-        int squareSize;
-
-        // Check if there is a valid explicitly set dimension first (prioritize width).
-        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY && measureWidth > 0) {
-            squareSize = measureWidth;
-        } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY
-                && measureHeight > 0) {
-            squareSize = measureHeight;
-        } else {
-            squareSize = Math.min(measureWidth, measureHeight);
-        }
-
-        int squareMeasureSpec = MeasureSpec.makeMeasureSpec(squareSize, MeasureSpec.EXACTLY);
-
-        super.onMeasure(squareMeasureSpec, squareMeasureSpec);
-    }
-}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java b/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java
index 0b935e856..177547b3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java
@@ -172,7 +172,7 @@
                 mUi.notifyDownloadPaused(info);
                 break;
             case OfflineItemState.FAILED:
-                mUi.notifyDownloadFailed(info, item.failState);
+                mUi.notifyDownloadFailed(info);
                 break;
             case OfflineItemState.PENDING:
                 mUi.notifyDownloadPaused(info);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteChooserDialogManager.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteChooserDialogManager.java
index 499f130ee..9d6f7d0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteChooserDialogManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteChooserDialogManager.java
@@ -4,10 +4,13 @@
 
 package org.chromium.chrome.browser.media.router;
 
+import android.content.Context;
 import android.content.DialogInterface;
+import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.app.DialogFragment;
 import android.support.v4.app.FragmentManager;
+import android.support.v7.app.MediaRouteChooserDialog;
 import android.support.v7.app.MediaRouteChooserDialogFragment;
 import android.support.v7.media.MediaRouteSelector;
 
@@ -47,6 +50,15 @@
         }
 
         @Override
+        public MediaRouteChooserDialog onCreateChooserDialog(
+                Context context, Bundle savedInstanceState) {
+            MediaRouteChooserDialog dialog =
+                    super.onCreateChooserDialog(context, savedInstanceState);
+            dialog.setCanceledOnTouchOutside(true);
+            return dialog;
+        }
+
+        @Override
         public void onStart() {
             mVisibilitySaver.saveSystemVisibility(getActivity());
             super.onStart();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteControllerDialogManager.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteControllerDialogManager.java
index c9d7f4bc..2602cb1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteControllerDialogManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteControllerDialogManager.java
@@ -4,10 +4,13 @@
 
 package org.chromium.chrome.browser.media.router;
 
+import android.content.Context;
 import android.content.DialogInterface;
+import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.app.DialogFragment;
 import android.support.v4.app.FragmentManager;
+import android.support.v7.app.MediaRouteControllerDialog;
 import android.support.v7.app.MediaRouteControllerDialogFragment;
 import android.support.v7.media.MediaRouteSelector;
 import android.support.v7.media.MediaRouter;
@@ -59,6 +62,15 @@
         }
 
         @Override
+        public MediaRouteControllerDialog onCreateControllerDialog(
+                Context context, Bundle savedInstanceState) {
+            MediaRouteControllerDialog dialog =
+                    super.onCreateControllerDialog(context, savedInstanceState);
+            dialog.setCanceledOnTouchOutside(true);
+            return dialog;
+        }
+
+        @Override
         public void onStart() {
             mVisibilitySaver.saveSystemVisibility(getActivity());
             super.onStart();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorController.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorController.java
index 500b10d..571e9aba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorController.java
@@ -144,6 +144,7 @@
         if (activity == null) return;
         if (!(activity instanceof ChromeActivity)) return;
         ChromeActivity chromeActivity = (ChromeActivity) activity;
+        if (chromeActivity.getSnackbarManager() == null) return;
 
         if (isOnline) {
             hideOfflineIndicator(chromeActivity);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteCoordinator.java
new file mode 100644
index 0000000..11f1d94
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/AutocompleteCoordinator.java
@@ -0,0 +1,986 @@
+// 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.omnibox;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.support.v4.view.ViewCompat;
+import android.text.TextUtils;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnLayoutChangeListener;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+import android.widget.ListView;
+
+import org.chromium.base.Log;
+import org.chromium.base.StrictModeContext;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordUserAction;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.omnibox.AutocompleteController.OnSuggestionsReceivedListener;
+import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxResultItem;
+import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxSuggestionDelegate;
+import org.chromium.chrome.browser.omnibox.OmniboxSuggestionsList.OmniboxSuggestionListEmbedder;
+import org.chromium.chrome.browser.omnibox.VoiceSuggestionProvider.VoiceResult;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
+import org.chromium.chrome.browser.toolbar.ToolbarPhone;
+import org.chromium.chrome.browser.util.KeyNavigationUtil;
+import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.UiUtils;
+import org.chromium.ui.base.PageTransition;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Coordinator that handles the interactions with the autocomplete system.
+ */
+public class AutocompleteCoordinator implements OnSuggestionsReceivedListener {
+    private static final String TAG = "cr_Autocomplete";
+
+    // Delay triggering the omnibox results upon key press to allow the location bar to repaint
+    // with the new characters.
+    private static final long OMNIBOX_SUGGESTION_START_DELAY_MS = 30;
+
+    private final Context mContext;
+    private final ViewGroup mParent;
+    private final AutocompleteDelegate mDelegate;
+    private final OmniboxSuggestionListEmbedder mSuggestionListEmbedder;
+    private final UrlBarEditingTextStateProvider mUrlBarEditingTextProvider;
+
+    private final OmniboxResultsAdapter mSuggestionListAdapter;
+    private final List<OmniboxResultItem> mSuggestionItems;
+    private final List<Runnable> mDeferredNativeRunnables = new ArrayList<Runnable>();
+
+    private ToolbarDataProvider mToolbarDataProvider;
+    private OmniboxSuggestionsList mSuggestionList;
+    private boolean mNativeInitialized;
+    private AutocompleteController mAutocomplete;
+    private boolean mSuggestionsShown;
+    private boolean mSuggestionModalShown;
+    private ViewGroup mOmniboxResultsContainer;
+
+    // The timestamp (using SystemClock.elapsedRealtime()) at the point when the user started
+    // modifying the omnibox with new input.
+    private long mNewOmniboxEditSessionTimestamp = -1;
+    // Set to true when the user has started typing new input in the omnibox, set to false
+    // when the omnibox loses focus or becomes empty.
+    private boolean mHasStartedNewOmniboxEditSession;
+
+    /**
+     * The text shown in the URL bar (user text + inline autocomplete) after the most recent set of
+     * omnibox suggestions was received. When the user presses enter in the omnibox, this value is
+     * compared to the URL bar text to determine whether the first suggestion is still valid.
+     */
+    private String mUrlTextAfterSuggestionsReceived;
+
+    private boolean mIgnoreOmniboxItemSelection = true;
+
+    private Runnable mShowSuggestions;
+    private Runnable mRequestSuggestions;
+    private DeferredOnSelectionRunnable mDeferredOnSelection;
+
+    private boolean mShowCachedZeroSuggestResults;
+    private boolean mShouldPreventOmniboxAutocomplete;
+
+    /**
+     * Provides the additional functionality to trigger and interact with autocomplete suggestions.
+     */
+    interface AutocompleteDelegate {
+        /**
+         * Notified that suggestions have changed.
+         * @param autocompleteText The inline autocomplete text that can be appended to the
+         *                         currently entered user text.
+         */
+        void onSuggestionsChanged(String autocompleteText);
+
+        /**
+         * Notified that the suggestions have been hidden.
+         */
+        void onSuggestionsHidden();
+
+        /**
+         * Requests the keyboard be hidden.
+         */
+        void hideKeyboard();
+
+        /**
+         * Requests that the given URL be loaded in the current tab.
+         *
+         * @param url The URL to be loaded.
+         * @param transition The transition type associated with the url load.
+         * @param inputStart The time the input started for the load request.
+         */
+        void loadUrl(String url, @PageTransition int transition, long inputStart);
+
+        /**
+         * Requests that the specified text be set as the current editing text in the omnibox.
+         */
+        void setOmniboxEditingText(String text);
+
+        /**
+         * @return Whether the omnibox was focused via the NTP fakebox.
+         */
+        boolean didFocusUrlFromFakebox();
+
+        /**
+         * @return Whether the URL currently has focus.
+         */
+        boolean isUrlBarFocused();
+
+        /**
+         * @return Whether a URL focus change animation is currently in progress.
+         */
+        boolean isUrlFocusChangeInProgress();
+    }
+
+    /**
+     * Constructs a coordinator for the autocomplete system.
+     *
+     * @param parent The UI parent component for the autocomplete UI.
+     * @param delegate The delegate to fulfill additional autocomplete requirements.
+     * @param listEmbedder The embedder for controlling the display constraints of the suggestions
+     *                     list.
+     * @param urlBarEditingTextProvider Provider of editing text state from the UrlBar.
+     */
+    public AutocompleteCoordinator(ViewGroup parent, AutocompleteDelegate delegate,
+            OmniboxSuggestionListEmbedder listEmbedder,
+            UrlBarEditingTextStateProvider urlBarEditingTextProvider) {
+        mParent = parent;
+        mContext = parent.getContext();
+        mDelegate = delegate;
+        mSuggestionListEmbedder = listEmbedder;
+        mUrlBarEditingTextProvider = urlBarEditingTextProvider;
+
+        mSuggestionItems = new ArrayList<OmniboxResultItem>();
+        mSuggestionListAdapter = new OmniboxResultsAdapter(mContext, mSuggestionItems);
+        mAutocomplete = new AutocompleteController(this);
+    }
+
+    /**
+     * Provides data and state for the toolbar component.
+     * @param toolbarDataProvider The data provider.
+     */
+    public void setToolbarDataProvider(ToolbarDataProvider toolbarDataProvider) {
+        mToolbarDataProvider = toolbarDataProvider;
+        mSuggestionListAdapter.setToolbarDataProvider(toolbarDataProvider);
+    }
+
+    /**
+     * Updates the profile used for generating autocomplete suggestions.
+     * @param profile The profile to be used.
+     */
+    public void setAutocompleteProfile(Profile profile) {
+        mAutocomplete.setProfile(profile);
+    }
+
+    /**
+     * Whether omnibox autocomplete should currently be prevented from generating suggestions.
+     */
+    public void setShouldPreventOmniboxAutocomplete(boolean prevent) {
+        mShouldPreventOmniboxAutocomplete = prevent;
+    }
+
+    /**
+     * @return The number of current autocomplete suggestions.
+     */
+    public int getSuggestionCount() {
+        return mSuggestionItems.size();
+    }
+
+    /**
+     * Retrieve the omnibox suggestion at the specified index.  The index represents the ordering
+     * in the underlying model.  The index does not represent visibility due to the current scroll
+     * position of the list.
+     *
+     * @param index The index of the suggestion to fetch.
+     * @return The suggestion at the given index.
+     */
+    public OmniboxSuggestion getSuggestionAt(int index) {
+        return mSuggestionItems.get(index).getSuggestion();
+    }
+
+    /**
+     * Signals that native initialization has completed.
+     */
+    public void onNativeInitialized() {
+        mNativeInitialized = true;
+
+        for (Runnable deferredRunnable : mDeferredNativeRunnables) {
+            mParent.post(deferredRunnable);
+        }
+        mDeferredNativeRunnables.clear();
+    }
+
+    /**
+     * @return The suggestion list popup containing the omnibox results (or null if it has not yet
+     *         been created).
+     */
+    @VisibleForTesting
+    public OmniboxSuggestionsList getSuggestionList() {
+        return mSuggestionList;
+    }
+
+    /**
+     * @return Whether the suggestions list is currently visible.
+     */
+    public boolean isSuggestionsListShown() {
+        return mSuggestionsShown;
+    }
+
+    /**
+     * @return Whether a modal dialog triggered from the suggestions is currently visible.
+     */
+    public boolean isSuggestionModalShown() {
+        return mSuggestionModalShown;
+    }
+
+    /**
+     * @return The view containing the suggestions list.
+     */
+    public View getSuggestionContainerView() {
+        return mOmniboxResultsContainer;
+    }
+
+    /**
+     * @see AutocompleteController#onVoiceResults(Bundle)
+     */
+    // TODO(tedchoc): Should this coordinator own the voice query logic too?
+    public VoiceResult onVoiceResults(Bundle data) {
+        return mAutocomplete.onVoiceResults(data);
+    }
+
+    /**
+     * @return The current native pointer to the autocomplete results.
+     */
+    // TODO(tedchoc): Figure out how to remove this.
+    long getCurrentNativeAutocompleteResult() {
+        return mAutocomplete.getCurrentNativeAutocompleteResult();
+    }
+
+    /**
+     * Initiates the mSuggestionListPopup.  Done on demand to not slow down the initial inflation of
+     * the location bar.
+     */
+    private void initSuggestionList() {
+        // Only called from onSuggestionsReceived(), which is a callback from a listener set up by
+        // onNativeLibraryReady(), so this assert is safe.
+        assert mNativeInitialized
+                || mShowCachedZeroSuggestResults
+            : "Trying to initialize native suggestions list before native init";
+        if (mSuggestionList != null) return;
+
+        OnLayoutChangeListener suggestionListResizer = new OnLayoutChangeListener() {
+            @Override
+            public void onLayoutChange(View v, int left, int top, int right, int bottom,
+                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
+                if (mSuggestionList.isShown()) mSuggestionList.updateLayoutParams();
+            }
+        };
+        // TODO(tedchoc): This should be passed in via the parent coordinator. Using findViewById
+        //                on the root view is working around component layering.
+        mParent.getRootView()
+                .findViewById(R.id.control_container)
+                .addOnLayoutChangeListener(suggestionListResizer);
+
+        // TODO(tedchoc): Investigate lazily building the suggestion list off of the UI thread.
+        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
+            mSuggestionList = new OmniboxSuggestionsList(mContext, mSuggestionListEmbedder);
+        }
+
+        // Ensure the results container is initialized and add the suggestion list to it.
+        initOmniboxResultsContainer();
+
+        // Start with visibility GONE to ensure that show() is called. http://crbug.com/517438
+        mSuggestionList.setVisibility(View.GONE);
+        mSuggestionList.setAdapter(mSuggestionListAdapter);
+        mSuggestionList.setClipToPadding(false);
+        mSuggestionListAdapter.setSuggestionDelegate(new OmniboxSuggestionDelegate() {
+            private long mLastActionUpTimestamp;
+
+            @Override
+            public void onSelection(OmniboxSuggestion suggestion, int position) {
+                if (mShowCachedZeroSuggestResults && !mNativeInitialized) {
+                    mDeferredOnSelection = new DeferredOnSelectionRunnable(suggestion, position) {
+                        @Override
+                        public void run() {
+                            onSelection(this.mSuggestion, this.mPosition);
+                        }
+                    };
+                    return;
+                }
+                String suggestionMatchUrl =
+                        updateSuggestionUrlIfNeeded(suggestion, position, false);
+                loadUrlFromOmniboxMatch(
+                        suggestionMatchUrl, position, suggestion, mLastActionUpTimestamp);
+                hideSuggestions();
+                mDelegate.hideKeyboard();
+            }
+
+            @Override
+            public void onRefineSuggestion(OmniboxSuggestion suggestion) {
+                stopAutocomplete(false);
+                boolean isUrlSuggestion = suggestion.isUrlSuggestion();
+                String refineText = suggestion.getFillIntoEdit();
+                if (!isUrlSuggestion) refineText = TextUtils.concat(refineText, " ").toString();
+
+                mDelegate.setOmniboxEditingText(refineText);
+                onTextChangedForAutocomplete();
+                if (isUrlSuggestion) {
+                    RecordUserAction.record("MobileOmniboxRefineSuggestion.Url");
+                } else {
+                    RecordUserAction.record("MobileOmniboxRefineSuggestion.Search");
+                }
+            }
+
+            @Override
+            public void onSetUrlToSuggestion(OmniboxSuggestion suggestion) {
+                if (mIgnoreOmniboxItemSelection) return;
+                mDelegate.setOmniboxEditingText(suggestion.getFillIntoEdit());
+                mIgnoreOmniboxItemSelection = true;
+            }
+
+            @Override
+            public void onDeleteSuggestion(OmniboxSuggestion suggestion, int position) {
+                if (mAutocomplete != null) {
+                    mAutocomplete.deleteSuggestion(position, suggestion.hashCode());
+                }
+            }
+
+            @Override
+            public void onGestureDown() {
+                stopAutocomplete(false);
+            }
+
+            @Override
+            public void onGestureUp(long timestamp) {
+                mLastActionUpTimestamp = timestamp;
+            }
+
+            @Override
+            public void onShowModal() {
+                mSuggestionModalShown = true;
+            }
+
+            @Override
+            public void onHideModal() {
+                mSuggestionModalShown = false;
+            }
+
+            @Override
+            public void onTextWidthsUpdated(float requiredWidth, float matchContentsWidth) {
+                mSuggestionList.updateMaxTextWidths(requiredWidth, matchContentsWidth);
+            }
+
+            @Override
+            public float getMaxRequiredWidth() {
+                return mSuggestionList.getMaxRequiredWidth();
+            }
+
+            @Override
+            public float getMaxMatchContentsWidth() {
+                return mSuggestionList.getMaxMatchContentsWidth();
+            }
+        });
+    }
+
+    /**
+     * Handles showing/hiding the suggestions list.
+     * @param visible Whether the suggestions list should be visible.
+     */
+    private void setSuggestionsListVisibility(final boolean visible) {
+        if (mSuggestionsShown == visible) return;
+        mSuggestionsShown = visible;
+        if (mSuggestionList != null) {
+            final boolean isShowing = mSuggestionList.isShown();
+            if (visible && !isShowing) {
+                mIgnoreOmniboxItemSelection = true; // Reset to default value.
+
+                if (mSuggestionList.getParent() == null) {
+                    mOmniboxResultsContainer.addView(mSuggestionList);
+                }
+
+                mSuggestionList.show();
+                updateSuggestionListLayoutDirection();
+            } else if (!visible && isShowing) {
+                mSuggestionList.setVisibility(View.GONE);
+
+                UiUtils.removeViewFromParent(mSuggestionList);
+            }
+        }
+        maybeShowOmniboxResultsContainer();
+    }
+
+    private void initOmniboxResultsContainer() {
+        if (mOmniboxResultsContainer != null) return;
+        ViewStub overlayStub =
+                (ViewStub) mParent.getRootView().findViewById(R.id.omnibox_results_container_stub);
+        mOmniboxResultsContainer = (ViewGroup) overlayStub.inflate();
+    }
+
+    /**
+     * Conditionally show the omnibox suggestions container.
+     */
+    void maybeShowOmniboxResultsContainer() {
+        if (isSuggestionsListShown() || mDelegate.isUrlBarFocused()) {
+            initOmniboxResultsContainer();
+            updateOmniboxResultsContainerVisibility(true);
+        }
+    }
+
+    /**
+     * Update whether the omnibox suggestions container is visible.
+     */
+    void updateOmniboxResultsContainerVisibility(boolean visible) {
+        if (mOmniboxResultsContainer == null) return;
+
+        boolean currentlyVisible = mOmniboxResultsContainer.getVisibility() == View.VISIBLE;
+        if (currentlyVisible == visible) return;
+
+        if (visible) {
+            mOmniboxResultsContainer.setVisibility(View.VISIBLE);
+        } else {
+            mOmniboxResultsContainer.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    /**
+     * Update the layout direction of the suggestion list based on the parent layout direction.
+     */
+    void updateSuggestionListLayoutDirection() {
+        if (mSuggestionList == null) return;
+        int layoutDirection = ViewCompat.getLayoutDirection(mParent);
+        mSuggestionList.updateSuggestionsLayoutDirection(layoutDirection);
+        mSuggestionListAdapter.setLayoutDirection(layoutDirection);
+    }
+
+    /**
+     * Handle the key events associated with the suggestion list.
+     *
+     * @param keyCode The keycode representing what key was interacted with.
+     * @param event The key event containing all meta-data associated with the event.
+     * @return Whether the key event was handled.
+     */
+    public boolean handleKeyEvent(int keyCode, KeyEvent event) {
+        if (KeyNavigationUtil.isGoDown(event) && mSuggestionList != null
+                && mSuggestionList.isShown()) {
+            int suggestionCount = mSuggestionListAdapter.getCount();
+            if (mSuggestionList.getSelectedItemPosition() < suggestionCount - 1) {
+                if (suggestionCount > 0) mIgnoreOmniboxItemSelection = false;
+            } else {
+                // Do not pass down events when the last item is already selected as it will
+                // dismiss the suggestion list.
+                return true;
+            }
+
+            if (mSuggestionList.getSelectedItemPosition() == ListView.INVALID_POSITION) {
+                // When clearing the selection after a text change, state is not reset
+                // correctly so hitting down again will cause it to start from the previous
+                // selection point. We still have to send the key down event to let the list
+                // view items take focus, but then we select the first item explicitly.
+                boolean result = mSuggestionList.onKeyDown(keyCode, event);
+                mSuggestionList.setSelection(0);
+                return result;
+            } else {
+                return mSuggestionList.onKeyDown(keyCode, event);
+            }
+        } else if (KeyNavigationUtil.isGoUp(event) && mSuggestionList != null
+                && mSuggestionList.isShown()) {
+            if (mSuggestionList.getSelectedItemPosition() != 0
+                    && mSuggestionListAdapter.getCount() > 0) {
+                mIgnoreOmniboxItemSelection = false;
+            }
+            return mSuggestionList.onKeyDown(keyCode, event);
+        } else if (KeyNavigationUtil.isGoRight(event) && mSuggestionList != null
+                && mSuggestionList.isShown()
+                && mSuggestionList.getSelectedItemPosition() != ListView.INVALID_POSITION) {
+            OmniboxResultItem selectedItem = (OmniboxResultItem) mSuggestionListAdapter.getItem(
+                    mSuggestionList.getSelectedItemPosition());
+            mDelegate.setOmniboxEditingText(selectedItem.getSuggestion().getFillIntoEdit());
+            onTextChangedForAutocomplete();
+            mSuggestionList.setSelection(0);
+            return true;
+        } else if (KeyNavigationUtil.isEnter(event) && mParent.getVisibility() == View.VISIBLE) {
+            mDelegate.hideKeyboard();
+            final String urlText = mUrlBarEditingTextProvider.getTextWithAutocomplete();
+            if (mNativeInitialized) {
+                findMatchAndLoadUrl(urlText, event.getEventTime());
+            } else {
+                mDeferredNativeRunnables.add(
+                        () -> findMatchAndLoadUrl(urlText, event.getEventTime()));
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private void findMatchAndLoadUrl(String urlText, long inputStart) {
+        int suggestionMatchPosition;
+        OmniboxSuggestion suggestionMatch;
+        boolean skipOutOfBoundsCheck = false;
+
+        if (mSuggestionList != null && mSuggestionList.isShown()
+                && mSuggestionList.getSelectedItemPosition() != ListView.INVALID_POSITION) {
+            // Bluetooth keyboard case: the user highlighted a suggestion with the arrow
+            // keys, then pressed enter.
+            suggestionMatchPosition = mSuggestionList.getSelectedItemPosition();
+            OmniboxResultItem selectedItem =
+                    (OmniboxResultItem) mSuggestionListAdapter.getItem(suggestionMatchPosition);
+            suggestionMatch = selectedItem.getSuggestion();
+        } else if (!mSuggestionItems.isEmpty()
+                && urlText.equals(mUrlTextAfterSuggestionsReceived)) {
+            // Common case: the user typed something, received suggestions, then pressed enter.
+            suggestionMatch = mSuggestionItems.get(0).getSuggestion();
+            suggestionMatchPosition = 0;
+        } else {
+            // Less common case: there are no valid omnibox suggestions. This can happen if the
+            // user tapped the URL bar to dismiss the suggestions, then pressed enter. This can
+            // also happen if the user presses enter before any suggestions have been received
+            // from the autocomplete controller.
+            suggestionMatch = mAutocomplete.classify(urlText, mDelegate.didFocusUrlFromFakebox());
+            suggestionMatchPosition = 0;
+            // Classify matches don't propagate to java, so skip the OOB check.
+            skipOutOfBoundsCheck = true;
+
+            // If urlText couldn't be classified, bail.
+            if (suggestionMatch == null) return;
+        }
+
+        String suggestionMatchUrl = updateSuggestionUrlIfNeeded(
+                suggestionMatch, suggestionMatchPosition, skipOutOfBoundsCheck);
+        loadUrlFromOmniboxMatch(
+                suggestionMatchUrl, suggestionMatchPosition, suggestionMatch, inputStart);
+    }
+
+    /**
+     * Updates the URL we will navigate to from suggestion, if needed. This will update the search
+     * URL to be of the corpus type if query in the omnibox is displayed and update aqs= parameter
+     * on regular web search URLs.
+     *
+     * @param suggestion The chosen omnibox suggestion.
+     * @param selectedIndex The index of the chosen omnibox suggestion.
+     * @param skipCheck Whether to skip an out of bounds check.
+     * @return The url to navigate to.
+     */
+    @SuppressWarnings("ReferenceEquality")
+    private String updateSuggestionUrlIfNeeded(
+            OmniboxSuggestion suggestion, int selectedIndex, boolean skipCheck) {
+        // Only called once we have suggestions, and don't have a listener though which we can
+        // receive suggestions until the native side is ready, so this is safe
+        assert mNativeInitialized
+            : "updateSuggestionUrlIfNeeded called before native initialization";
+
+        String updatedUrl = null;
+        if (suggestion.getType() != OmniboxSuggestionType.VOICE_SUGGEST) {
+            int verifiedIndex = -1;
+            if (!skipCheck) {
+                if (mSuggestionItems.size() > selectedIndex
+                        && mSuggestionItems.get(selectedIndex).getSuggestion() == suggestion) {
+                    verifiedIndex = selectedIndex;
+                } else {
+                    // Underlying omnibox results may have changed since the selection was made,
+                    // find the suggestion item, if possible.
+                    for (int i = 0; i < mSuggestionItems.size(); i++) {
+                        if (suggestion.equals(mSuggestionItems.get(i).getSuggestion())) {
+                            verifiedIndex = i;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            // If we do not have the suggestion as part of our results, skip the URL update.
+            if (verifiedIndex == -1) return suggestion.getUrl();
+
+            // TODO(mariakhomenko): Ideally we want to update match destination URL with new aqs
+            // for query in the omnibox and voice suggestions, but it's currently difficult to do.
+            long elapsedTimeSinceInputChange = mNewOmniboxEditSessionTimestamp > 0
+                    ? (SystemClock.elapsedRealtime() - mNewOmniboxEditSessionTimestamp)
+                    : -1;
+            updatedUrl = mAutocomplete.updateMatchDestinationUrlWithQueryFormulationTime(
+                    verifiedIndex, suggestion.hashCode(), elapsedTimeSinceInputChange);
+        }
+
+        return updatedUrl == null ? suggestion.getUrl() : updatedUrl;
+    }
+
+    /**
+     * Notifies the autocomplete system that the text has changed that drives autocomplete and the
+     * autocomplete suggestions should be updated.
+     */
+    public void onTextChangedForAutocomplete() {
+        if (mShouldPreventOmniboxAutocomplete) return;
+
+        cancelPendingAutocompleteStart();
+
+        if (!mHasStartedNewOmniboxEditSession && mNativeInitialized) {
+            mAutocomplete.resetSession();
+            mNewOmniboxEditSessionTimestamp = SystemClock.elapsedRealtime();
+            mHasStartedNewOmniboxEditSession = true;
+        }
+
+        if (!mParent.isInTouchMode() && mSuggestionList != null) {
+            mSuggestionList.setSelection(0);
+        }
+
+        stopAutocomplete(false);
+        if (TextUtils.isEmpty(mUrlBarEditingTextProvider.getTextWithoutAutocomplete())) {
+            // crbug.com/764749
+            Log.w(TAG, "onTextChangedForAutocomplete: url is empty");
+            hideSuggestions();
+            startZeroSuggest();
+        } else {
+            assert mRequestSuggestions == null : "Multiple omnibox requests in flight.";
+            mRequestSuggestions = () -> {
+                String textWithoutAutocomplete =
+                        mUrlBarEditingTextProvider.getTextWithoutAutocomplete();
+                boolean preventAutocomplete = !mUrlBarEditingTextProvider.shouldAutocomplete();
+                mRequestSuggestions = null;
+
+                if (!mToolbarDataProvider.hasTab()) {
+                    // crbug.com/764749
+                    Log.w(TAG, "onTextChangedForAutocomplete: no tab");
+                    return;
+                }
+
+                Profile profile = mToolbarDataProvider.getProfile();
+                int cursorPosition = -1;
+                if (mUrlBarEditingTextProvider.getSelectionStart()
+                        == mUrlBarEditingTextProvider.getSelectionEnd()) {
+                    // Conveniently, if there is no selection, those two functions return -1,
+                    // exactly the same value needed to pass to start() to indicate no cursor
+                    // position.  Hence, there's no need to check for -1 here explicitly.
+                    cursorPosition = mUrlBarEditingTextProvider.getSelectionStart();
+                }
+                mAutocomplete.start(profile, mToolbarDataProvider.getCurrentUrl(),
+                        textWithoutAutocomplete, cursorPosition, preventAutocomplete,
+                        mDelegate.didFocusUrlFromFakebox());
+            };
+            if (mNativeInitialized) {
+                mParent.postDelayed(mRequestSuggestions, OMNIBOX_SUGGESTION_START_DELAY_MS);
+            } else {
+                mDeferredNativeRunnables.add(mRequestSuggestions);
+            }
+        }
+    }
+
+    @Override
+    public void onSuggestionsReceived(
+            List<OmniboxSuggestion> newSuggestions, String inlineAutocompleteText) {
+        if (mShouldPreventOmniboxAutocomplete) return;
+
+        // This is a callback from a listener that is set up by onNativeLibraryReady,
+        // so can only be called once the native side is set up unless we are showing
+        // cached java-only suggestions.
+        assert mNativeInitialized
+                || mShowCachedZeroSuggestResults
+            : "Native suggestions received before native side intialialized";
+
+        if (mDeferredOnSelection != null) {
+            mDeferredOnSelection.setShouldLog(newSuggestions.size() > mDeferredOnSelection.mPosition
+                    && mDeferredOnSelection.mSuggestion.equals(
+                               newSuggestions.get(mDeferredOnSelection.mPosition)));
+            mDeferredOnSelection.run();
+            mDeferredOnSelection = null;
+        }
+        String userText = mUrlBarEditingTextProvider.getTextWithoutAutocomplete();
+        mUrlTextAfterSuggestionsReceived = userText + inlineAutocompleteText;
+
+        boolean itemsChanged = false;
+        boolean itemCountChanged = false;
+        // If the length of the incoming suggestions matches that of those currently being shown,
+        // replace them inline to allow transient entries to retain their proper highlighting.
+        if (mSuggestionItems.size() == newSuggestions.size()) {
+            for (int index = 0; index < newSuggestions.size(); index++) {
+                OmniboxResultItem suggestionItem = mSuggestionItems.get(index);
+                OmniboxSuggestion suggestion = suggestionItem.getSuggestion();
+                OmniboxSuggestion newSuggestion = newSuggestions.get(index);
+                // Determine whether the suggestions have changed. If not, save some time by not
+                // redrawing the suggestions UI.
+                if (suggestion.equals(newSuggestion)
+                        && suggestion.getType() != OmniboxSuggestionType.SEARCH_SUGGEST_TAIL) {
+                    if (suggestionItem.getMatchedQuery().equals(userText)) {
+                        continue;
+                    } else if (!suggestion.getDisplayText().startsWith(userText)
+                            && !suggestion.getUrl().contains(userText)) {
+                        continue;
+                    }
+                }
+                mSuggestionItems.set(index, new OmniboxResultItem(newSuggestion, userText));
+                itemsChanged = true;
+            }
+        } else {
+            itemsChanged = true;
+            itemCountChanged = true;
+            clearSuggestions(false);
+            for (int i = 0; i < newSuggestions.size(); i++) {
+                mSuggestionItems.add(new OmniboxResultItem(newSuggestions.get(i), userText));
+            }
+        }
+
+        if (mSuggestionItems.isEmpty()) {
+            if (mSuggestionsShown) {
+                hideSuggestions();
+            } else {
+                mSuggestionListAdapter.notifySuggestionsChanged();
+            }
+            return;
+        }
+
+        mDelegate.onSuggestionsChanged(inlineAutocompleteText);
+
+        // Show the suggestion list.
+        initSuggestionList(); // It may not have been initialized yet.
+        mSuggestionList.resetMaxTextWidths();
+
+        if (itemsChanged) mSuggestionListAdapter.notifySuggestionsChanged();
+
+        if (mDelegate.isUrlBarFocused()) {
+            final boolean updateLayoutParams = itemCountChanged || mShowSuggestions != null;
+            if (mShowSuggestions != null) mParent.removeCallbacks(mShowSuggestions);
+            mShowSuggestions = () -> {
+                setSuggestionsListVisibility(true);
+                if (updateLayoutParams) mSuggestionList.updateLayoutParams();
+                mShowSuggestions = null;
+            };
+            if (!mDelegate.isUrlFocusChangeInProgress()) {
+                mShowSuggestions.run();
+            } else {
+                mParent.postDelayed(
+                        mShowSuggestions, ToolbarPhone.URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
+            }
+        }
+    }
+
+    private void loadUrlFromOmniboxMatch(
+            String url, int matchPosition, OmniboxSuggestion suggestion, long inputStart) {
+        // loadUrl modifies AutocompleteController's state clearing the native
+        // AutocompleteResults needed by onSuggestionsSelected. Therefore,
+        // loadUrl should should be invoked last.
+        int transition = suggestion.getTransition();
+        int type = suggestion.getType();
+        String currentPageUrl = mToolbarDataProvider.getCurrentUrl();
+        WebContents webContents = mToolbarDataProvider.hasTab()
+                ? mToolbarDataProvider.getTab().getWebContents()
+                : null;
+        long elapsedTimeSinceModified = mNewOmniboxEditSessionTimestamp > 0
+                ? (SystemClock.elapsedRealtime() - mNewOmniboxEditSessionTimestamp)
+                : -1;
+        boolean shouldSkipNativeLog = mShowCachedZeroSuggestResults
+                && (mDeferredOnSelection != null) && !mDeferredOnSelection.shouldLog();
+        if (!shouldSkipNativeLog) {
+            int autocompleteLength = mUrlBarEditingTextProvider.getTextWithAutocomplete().length()
+                    - mUrlBarEditingTextProvider.getTextWithoutAutocomplete().length();
+            mAutocomplete.onSuggestionSelected(matchPosition, suggestion.hashCode(), type,
+                    currentPageUrl, mDelegate.didFocusUrlFromFakebox(), elapsedTimeSinceModified,
+                    autocompleteLength, webContents);
+        }
+        if (((transition & PageTransition.CORE_MASK) == PageTransition.TYPED)
+                && TextUtils.equals(url, mToolbarDataProvider.getCurrentUrl())) {
+            // When the user hit enter on the existing permanent URL, treat it like a
+            // reload for scoring purposes.  We could detect this by just checking
+            // user_input_in_progress_, but it seems better to treat "edits" that end
+            // up leaving the URL unchanged (e.g. deleting the last character and then
+            // retyping it) as reloads too.  We exclude non-TYPED transitions because if
+            // the transition is GENERATED, the user input something that looked
+            // different from the current URL, even if it wound up at the same place
+            // (e.g. manually retyping the same search query), and it seems wrong to
+            // treat this as a reload.
+            transition = PageTransition.RELOAD;
+        } else if (type == OmniboxSuggestionType.URL_WHAT_YOU_TYPED
+                && mUrlBarEditingTextProvider.wasLastEditPaste()) {
+            // It's important to use the page transition from the suggestion or we might end
+            // up saving generated URLs as typed URLs, which would then pollute the subsequent
+            // omnibox results. There is one special case where the suggestion text was pasted,
+            // where we want the transition type to be LINK.
+
+            transition = PageTransition.LINK;
+        }
+        mDelegate.loadUrl(url, transition, inputStart);
+    }
+
+    /**
+     * Make a zero suggest request if:
+     * - Native is loaded.
+     * - The URL bar has focus.
+     * - The current tab is not incognito.
+     */
+    public void startZeroSuggest() {
+        // hasWindowFocus() can return true before onWindowFocusChanged has been called, so this
+        // is an optimization, but not entirely reliable.  The underlying controller needs to also
+        // ensure we do not double trigger zero query.
+        if (!mParent.hasWindowFocus()) return;
+
+        // Reset "edited" state in the omnibox if zero suggest is triggered -- new edits
+        // now count as a new session.
+        mHasStartedNewOmniboxEditSession = false;
+        mNewOmniboxEditSessionTimestamp = -1;
+        if (mNativeInitialized && mDelegate.isUrlBarFocused() && mToolbarDataProvider.hasTab()) {
+            mAutocomplete.startZeroSuggest(mToolbarDataProvider.getProfile(),
+                    mUrlBarEditingTextProvider.getTextWithAutocomplete(),
+                    mToolbarDataProvider.getCurrentUrl(), mToolbarDataProvider.getTitle(),
+                    mDelegate.didFocusUrlFromFakebox());
+        }
+    }
+
+    /**
+     * Sets to show cached zero suggest results. This will start both caching zero suggest results
+     * in shared preferences and also attempt to show them when appropriate without needing native
+     * initialization. See {@link #showCachedZeroSuggestResultsIfAvailable()} for
+     * showing the loaded results before native initialization.
+     * @param showCachedZeroSuggestResults Whether cached zero suggest should be shown.
+     */
+    public void setShowCachedZeroSuggestResults(boolean showCachedZeroSuggestResults) {
+        mShowCachedZeroSuggestResults = showCachedZeroSuggestResults;
+        if (mShowCachedZeroSuggestResults) mAutocomplete.startCachedZeroSuggest();
+    }
+
+    /**
+     * Signals the omnibox to shows the cached zero suggest results if they have been loaded from
+     * cache successfully.
+     */
+    public void showCachedZeroSuggestResultsIfAvailable() {
+        if (!mShowCachedZeroSuggestResults || mSuggestionList == null) return;
+        setSuggestionsListVisibility(true);
+        mSuggestionList.updateLayoutParams();
+    }
+
+    /**
+     * Update the visuals of the autocomplete UI.
+     * @param useDarkColors Whether dark colors should be applied to the UI.
+     */
+    public void updateVisualsForState(boolean useDarkColors) {
+        if (mSuggestionList != null) {
+            mSuggestionList.refreshPopupBackground();
+        }
+        mSuggestionListAdapter.setUseDarkColors(useDarkColors);
+    }
+
+    private void clearSuggestions(boolean notifyChange) {
+        mSuggestionItems.clear();
+        // Make sure to notify the adapter. If the ListView becomes out of sync
+        // with its adapter and it has not been notified, it will throw an
+        // exception when some UI events are propagated.
+        if (notifyChange) mSuggestionListAdapter.notifyDataSetChanged();
+    }
+
+    /**
+     * Hides the omnibox suggestion popup.
+     *
+     * <p>
+     * Signals the autocomplete controller to stop generating omnibox suggestions.
+     *
+     * @see AutocompleteController#stop(boolean)
+     */
+    public void hideSuggestions() {
+        if (mAutocomplete == null || !mNativeInitialized) return;
+
+        if (mShowSuggestions != null) mParent.removeCallbacks(mShowSuggestions);
+
+        stopAutocomplete(true);
+
+        setSuggestionsListVisibility(false);
+        clearSuggestions(true);
+    }
+
+    /**
+     * Signals the autocomplete controller to stop generating omnibox suggestions and cancels the
+     * queued task to start the autocomplete controller, if any.
+     *
+     * @param clear Whether to clear the most recent autocomplete results.
+     */
+    public void stopAutocomplete(boolean clear) {
+        if (mAutocomplete != null) mAutocomplete.stop(clear);
+        cancelPendingAutocompleteStart();
+    }
+
+    /**
+     * Cancels the queued task to start the autocomplete controller, if any.
+     */
+    @VisibleForTesting
+    void cancelPendingAutocompleteStart() {
+        if (mRequestSuggestions != null) {
+            // There is a request for suggestions either waiting for the native side
+            // to start, or on the message queue. Remove it from wherever it is.
+            if (!mDeferredNativeRunnables.remove(mRequestSuggestions)) {
+                mParent.removeCallbacks(mRequestSuggestions);
+            }
+            mRequestSuggestions = null;
+        }
+    }
+
+    /**
+     * Trigger autocomplete for the given query.
+     */
+    void startAutocompleteForQuery(String query) {
+        stopAutocomplete(false);
+        if (mToolbarDataProvider.hasTab()) {
+            mAutocomplete.start(mToolbarDataProvider.getProfile(),
+                    mToolbarDataProvider.getCurrentUrl(), query, -1, false, false);
+        }
+    }
+
+    /**
+     * Notifies autocomplete that the URL focus state has changed.
+     */
+    void onUrlFocusChanged(boolean hasFocus) {
+        if (!hasFocus) {
+            mHasStartedNewOmniboxEditSession = false;
+            mNewOmniboxEditSessionTimestamp = -1;
+            hideSuggestions();
+        }
+
+        if (mNativeInitialized) {
+            startZeroSuggest();
+        } else {
+            mDeferredNativeRunnables.add(() -> {
+                if (TextUtils.isEmpty(mUrlBarEditingTextProvider.getTextWithAutocomplete())) {
+                    startZeroSuggest();
+                }
+            });
+        }
+    }
+
+    /**
+     * Sets the autocomplete controller for the location bar.
+     *
+     * @param controller The controller that will handle autocomplete/omnibox suggestions.
+     * @note Only used for testing.
+     */
+    @VisibleForTesting
+    public void setAutocompleteController(AutocompleteController controller) {
+        if (mAutocomplete != null) stopAutocomplete(true);
+        mAutocomplete = controller;
+    }
+
+    private static abstract class DeferredOnSelectionRunnable implements Runnable {
+        protected final OmniboxSuggestion mSuggestion;
+        protected final int mPosition;
+        protected boolean mShouldLog;
+
+        public DeferredOnSelectionRunnable(OmniboxSuggestion suggestion, int position) {
+            this.mSuggestion = suggestion;
+            this.mPosition = position;
+        }
+
+        /**
+         * Set whether the selection matches with native results for logging to make sense.
+         * @param log Whether the selection should be logged in native code.
+         */
+        public void setShouldLog(boolean log) {
+            mShouldLog = log;
+        }
+
+        /**
+         * @return Whether the selection should be logged in native code.
+         */
+        public boolean shouldLog() {
+            return mShouldLog;
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index b43056d..dd32575 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -16,7 +16,6 @@
 import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
-import android.os.SystemClock;
 import android.support.annotation.DrawableRes;
 import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
@@ -33,19 +32,16 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
-import android.view.ViewStub;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.ListView;
 import android.widget.TextView;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.CommandLine;
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
-import org.chromium.base.StrictModeContext;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
@@ -59,9 +55,7 @@
 import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.ntp.NewTabPage.FakeboxDelegate;
 import org.chromium.chrome.browser.ntp.NewTabPageUma;
-import org.chromium.chrome.browser.omnibox.AutocompleteController.OnSuggestionsReceivedListener;
-import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxResultItem;
-import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxSuggestionDelegate;
+import org.chromium.chrome.browser.omnibox.AutocompleteCoordinator.AutocompleteDelegate;
 import org.chromium.chrome.browser.omnibox.UrlBar.ScrollType;
 import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState;
 import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader;
@@ -73,16 +67,12 @@
 import org.chromium.chrome.browser.toolbar.ToolbarActionModeCallback;
 import org.chromium.chrome.browser.toolbar.ToolbarDataProvider;
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
-import org.chromium.chrome.browser.toolbar.ToolbarPhone;
 import org.chromium.chrome.browser.util.ColorUtils;
-import org.chromium.chrome.browser.util.KeyNavigationUtil;
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.browser.widget.ScrimView.ScrimParams;
 import org.chromium.chrome.browser.widget.TintedDrawable;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheet;
 import org.chromium.content_public.browser.LoadUrlParams;
-import org.chromium.content_public.browser.WebContents;
-import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
@@ -97,14 +87,10 @@
  * search terms.
  */
 public class LocationBarLayout extends FrameLayout
-        implements OnClickListener, OnSuggestionsReceivedListener, LocationBar, FakeboxDelegate,
+        implements OnClickListener, LocationBar, AutocompleteDelegate, FakeboxDelegate,
                    ScrimView.ScrimObserver, LocationBarVoiceRecognitionHandler.Delegate {
     private static final String TAG = "cr_LocationBar";
 
-    // Delay triggering the omnibox results upon key press to allow the location bar to repaint
-    // with the new characters.
-    private static final long OMNIBOX_SUGGESTION_START_DELAY_MS = 30;
-
     private final int mLightScrimColor;
 
     /** Params that control how the location bar interacts with the scrim. */
@@ -121,8 +107,8 @@
     /** A handle to the bottom sheet for chrome home. */
     protected BottomSheet mBottomSheet;
 
-    private AutocompleteController mAutocomplete;
     protected UrlBarCoordinator mUrlCoordinator;
+    private AutocompleteCoordinator mAutocompleteCoordinator;
 
     protected ToolbarDataProvider mToolbarDataProvider;
     private ObserverList<UrlFocusChangeListener> mUrlFocusChangeListeners = new ObserverList<>();
@@ -138,31 +124,13 @@
     @DrawableRes
     private int mSecurityIconResource;
 
-    private final OmniboxResultsAdapter mSuggestionListAdapter;
-    private OmniboxSuggestionsList mSuggestionList;
-
-    private final List<OmniboxResultItem> mSuggestionItems;
-
-    /**
-     * The text shown in the URL bar (user text + inline autocomplete) after the most recent set of
-     * omnibox suggestions was received. When the user presses enter in the omnibox, this value is
-     * compared to the URL bar text to determine whether the first suggestion is still valid.
-     */
-    private String mUrlTextAfterSuggestionsReceived;
-
-    private boolean mIgnoreOmniboxItemSelection = true;
-
     private String mOriginalUrl = "";
 
     private WindowAndroid mWindowAndroid;
     private WindowDelegate mWindowDelegate;
 
-    private Runnable mRequestSuggestions;
-
-    private ViewGroup mOmniboxResultsContainer;
     private ScrimView mScrim;
 
-    private boolean mSuggestionsShown;
     private boolean mUrlHasFocus;
     protected boolean mUrlFocusChangeInProgress;
     private boolean mUrlFocusedFromFakebox;
@@ -170,13 +138,6 @@
 
     private boolean mVoiceSearchEnabled;
 
-    // Set to true when the user has started typing new input in the omnibox, set to false
-    // when the omnibox loses focus or becomes empty.
-    private boolean mHasStartedNewOmniboxEditSession;
-    // The timestamp (using SystemClock.elapsedRealtime()) at the point when the user started
-    // modifying the omnibox with new input.
-    private long mNewOmniboxEditSessionTimestamp = -1;
-
     @LocationBarButtonType private int mLocationBarButtonType;
 
     private AnimatorSet mLocationBarIconActiveAnimator;
@@ -185,47 +146,14 @@
 
     private OmniboxPrerender mOmniboxPrerender;
 
-    private boolean mSuggestionModalShown;
     private boolean mUseDarkColors;
 
-    private Runnable mShowSuggestions;
-
-    private boolean mShowCachedZeroSuggestResults;
-
-    private DeferredOnSelectionRunnable mDeferredOnSelection;
-
     private boolean mOmniboxVoiceSearchAlwaysVisible;
     protected float mUrlFocusChangePercent;
     protected LinearLayout mUrlActionContainer;
 
     protected LocationBarVoiceRecognitionHandler mVoiceRecognitionHandler;
 
-    private static abstract class DeferredOnSelectionRunnable implements Runnable {
-        protected final OmniboxSuggestion mSuggestion;
-        protected final int mPosition;
-        protected boolean mShouldLog;
-
-        public DeferredOnSelectionRunnable(OmniboxSuggestion suggestion, int position) {
-            this.mSuggestion = suggestion;
-            this.mPosition = position;
-        }
-
-        /**
-         * Set whether the selection matches with native results for logging to make sense.
-         * @param log Whether the selection should be logged in native code.
-         */
-        public void setShouldLog(boolean log) {
-            mShouldLog = log;
-        }
-
-        /**
-         * @return Whether the selection should be logged in native code.
-         */
-        public boolean shouldLog() {
-            return mShouldLog;
-        }
-    }
-
     /**
      * Class to handle input from a hardware keyboard when the focus is on the URL bar. In
      * particular, handle navigating the suggestions list from the keyboard.
@@ -233,66 +161,7 @@
     private final class UrlBarKeyListener implements OnKeyListener {
         @Override
         public boolean onKey(View v, int keyCode, KeyEvent event) {
-            if (KeyNavigationUtil.isGoDown(event)
-                    && mSuggestionList != null
-                    && mSuggestionList.isShown()) {
-                int suggestionCount = mSuggestionListAdapter.getCount();
-                if (mSuggestionList.getSelectedItemPosition() < suggestionCount - 1) {
-                    if (suggestionCount > 0) mIgnoreOmniboxItemSelection = false;
-                } else {
-                    // Do not pass down events when the last item is already selected as it will
-                    // dismiss the suggestion list.
-                    return true;
-                }
-
-                if (mSuggestionList.getSelectedItemPosition()
-                        == ListView.INVALID_POSITION) {
-                    // When clearing the selection after a text change, state is not reset
-                    // correctly so hitting down again will cause it to start from the previous
-                    // selection point. We still have to send the key down event to let the list
-                    // view items take focus, but then we select the first item explicitly.
-                    boolean result = mSuggestionList.onKeyDown(keyCode, event);
-                    mSuggestionList.setSelection(0);
-                    return result;
-                } else {
-                    return mSuggestionList.onKeyDown(keyCode, event);
-                }
-            } else if (KeyNavigationUtil.isGoUp(event)
-                    && mSuggestionList != null
-                    && mSuggestionList.isShown()) {
-                if (mSuggestionList.getSelectedItemPosition() != 0
-                        && mSuggestionListAdapter.getCount() > 0) {
-                    mIgnoreOmniboxItemSelection = false;
-                }
-                return mSuggestionList.onKeyDown(keyCode, event);
-            } else if (KeyNavigationUtil.isGoRight(event)
-                    && mSuggestionList != null
-                    && mSuggestionList.isShown()
-                    && mSuggestionList.getSelectedItemPosition()
-                            != ListView.INVALID_POSITION) {
-                OmniboxResultItem selectedItem =
-                        (OmniboxResultItem) mSuggestionListAdapter.getItem(
-                                mSuggestionList.getSelectedItemPosition());
-                setUrlBarText(
-                        UrlBarData.forNonUrlText(selectedItem.getSuggestion().getFillIntoEdit()),
-                        UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_END);
-                onTextChangedForAutocomplete();
-                mSuggestionList.setSelection(0);
-                return true;
-            } else if (KeyNavigationUtil.isEnter(event)
-                    && LocationBarLayout.this.getVisibility() == VISIBLE) {
-                getWindowAndroid().getKeyboardDelegate().hideKeyboard(mUrlBar);
-                final String urlText = mUrlCoordinator.getTextWithAutocomplete();
-                if (mNativeInitialized) {
-                    findMatchAndLoadUrl(urlText, event.getEventTime());
-                } else {
-                    mDeferredNativeRunnables.add(new Runnable() {
-                        @Override
-                        public void run() {
-                            findMatchAndLoadUrl(urlText, event.getEventTime());
-                        }
-                    });
-                }
+            if (mAutocompleteCoordinator.handleKeyEvent(keyCode, event)) {
                 return true;
             } else if (keyCode == KeyEvent.KEYCODE_BACK) {
                 if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
@@ -314,46 +183,6 @@
             }
             return false;
         }
-
-        private void findMatchAndLoadUrl(String urlText, long inputStart) {
-            int suggestionMatchPosition;
-            OmniboxSuggestion suggestionMatch;
-            boolean skipOutOfBoundsCheck = false;
-
-            if (mSuggestionList != null
-                    && mSuggestionList.isShown()
-                    && mSuggestionList.getSelectedItemPosition()
-                    != ListView.INVALID_POSITION) {
-                // Bluetooth keyboard case: the user highlighted a suggestion with the arrow
-                // keys, then pressed enter.
-                suggestionMatchPosition = mSuggestionList.getSelectedItemPosition();
-                OmniboxResultItem selectedItem =
-                        (OmniboxResultItem) mSuggestionListAdapter.getItem(suggestionMatchPosition);
-                suggestionMatch = selectedItem.getSuggestion();
-            } else if (!mSuggestionItems.isEmpty()
-                    && urlText.equals(mUrlTextAfterSuggestionsReceived)) {
-                // Common case: the user typed something, received suggestions, then pressed enter.
-                suggestionMatch = mSuggestionItems.get(0).getSuggestion();
-                suggestionMatchPosition = 0;
-            } else {
-                // Less common case: there are no valid omnibox suggestions. This can happen if the
-                // user tapped the URL bar to dismiss the suggestions, then pressed enter. This can
-                // also happen if the user presses enter before any suggestions have been received
-                // from the autocomplete controller.
-                suggestionMatch = mAutocomplete.classify(urlText, mUrlFocusedFromFakebox);
-                suggestionMatchPosition = 0;
-                // Classify matches don't propagate to java, so skip the OOB check.
-                skipOutOfBoundsCheck = true;
-
-                // If urlText couldn't be classified, bail.
-                if (suggestionMatch == null) return;
-            }
-
-            String suggestionMatchUrl = updateSuggestionUrlIfNeeded(suggestionMatch,
-                        suggestionMatchPosition, skipOutOfBoundsCheck);
-            loadUrlFromOmniboxMatch(
-                    suggestionMatchUrl, suggestionMatchPosition, suggestionMatch, inputStart);
-        }
     }
 
     /**
@@ -407,8 +236,40 @@
         mUrlCoordinator = new UrlBarCoordinator((UrlBar) mUrlBar);
         mUrlCoordinator.setDelegate(this);
 
-        mSuggestionItems = new ArrayList<OmniboxResultItem>();
-        mSuggestionListAdapter = new OmniboxResultsAdapter(getContext(), mSuggestionItems);
+        OmniboxSuggestionsList.OmniboxSuggestionListEmbedder embedder =
+                new OmniboxSuggestionsList.OmniboxSuggestionListEmbedder() {
+                    @Override
+                    public boolean isTablet() {
+                        return mIsTablet;
+                    }
+
+                    @Override
+                    public boolean isIncognito() {
+                        return mToolbarDataProvider.isIncognito();
+                    }
+
+                    @Override
+                    public WindowDelegate getWindowDelegate() {
+                        return mWindowDelegate;
+                    }
+
+                    @Override
+                    public BottomSheet getBottomSheet() {
+                        return mBottomSheet;
+                    }
+
+                    @Override
+                    public View getAnchorView() {
+                        return getRootView().findViewById(R.id.toolbar);
+                    }
+
+                    @Override
+                    public View getAlignmentView() {
+                        return mIsTablet ? LocationBarLayout.this : null;
+                    }
+                };
+        mAutocompleteCoordinator =
+                new AutocompleteCoordinator(this, this, embedder, mUrlCoordinator);
 
         mMicButton = (AppCompatImageButton) findViewById(R.id.mic_button);
 
@@ -419,7 +280,7 @@
 
     @Override
     public boolean isSuggestionsListShown() {
-        return mSuggestionsShown;
+        return mAutocompleteCoordinator.isSuggestionsListShown();
     }
 
     @Override
@@ -474,7 +335,7 @@
             @Override
             public void onUrlDirectionChanged(int layoutDirection) {
                 ViewCompat.setLayoutDirection(LocationBarLayout.this, layoutDirection);
-                updateSuggestionListLayoutDirection();
+                mAutocompleteCoordinator.updateSuggestionListLayoutDirection();
             }
         });
     }
@@ -515,29 +376,6 @@
         mWindowAndroid = windowAndroid;
 
         mUrlCoordinator.setWindowDelegate(windowDelegate);
-        mAutocomplete = new AutocompleteController(this);
-    }
-
-    /**
-     * Sets to show cached zero suggest results. This will start both caching zero suggest results
-     * in shared preferences and also attempt to show them when appropriate without needing native
-     * initialization. See {@link LocationBarLayout#showCachedZeroSuggestResultsIfAvailable()} for
-     * showing the loaded results before native initialization.
-     * @param showCachedZeroSuggestResults Whether cached zero suggest should be shown.
-     */
-    public void setShowCachedZeroSuggestResults(boolean showCachedZeroSuggestResults) {
-        mShowCachedZeroSuggestResults = showCachedZeroSuggestResults;
-        if (mShowCachedZeroSuggestResults) mAutocomplete.startCachedZeroSuggest();
-    }
-
-    /**
-     * Signals the omnibox to shows the cached zero suggest results if they have been loaded from
-     * cache successfully.
-     */
-    public void showCachedZeroSuggestResultsIfAvailable() {
-        if (!mShowCachedZeroSuggestResults || mSuggestionList == null) return;
-        setSuggestionsListVisibility(true);
-        mSuggestionList.updateLayoutParams();
     }
 
     /**
@@ -556,6 +394,11 @@
         return mWindowDelegate;
     }
 
+    @Override
+    public AutocompleteCoordinator getAutocompleteCoordinator() {
+        return mAutocompleteCoordinator;
+    }
+
     /**
      * Handles native dependent initialization for this class.
      */
@@ -563,6 +406,7 @@
     public void onNativeLibraryReady() {
         mNativeInitialized = true;
 
+        mAutocompleteCoordinator.onNativeInitialized();
         mSecurityButton.setOnClickListener(this);
         mNavigationButton.setOnClickListener(this);
         mVerboseStatusTextView.setOnClickListener(this);
@@ -592,18 +436,6 @@
     }
 
     /**
-     * Sets the autocomplete controller for the location bar.
-     *
-     * @param controller The controller that will handle autocomplete/omnibox suggestions.
-     * @note Only used for testing.
-     */
-    @VisibleForTesting
-    public void setAutocompleteController(AutocompleteController controller) {
-        if (mAutocomplete != null) stopAutocomplete(true);
-        mAutocomplete = controller;
-    }
-
-    /**
      * Updates the profile used for generating autocomplete suggestions.
      * @param profile The profile to be used.
      */
@@ -614,7 +446,7 @@
         // call to onNativeLibraryReady, so this assert will not fire.
         assert mNativeInitialized
                 : "Setting Autocomplete Profile before native side initialized";
-        mAutocomplete.setProfile(profile);
+        mAutocompleteCoordinator.setAutocompleteProfile(profile);
         mOmniboxPrerender.initializeForProfile(profile);
     }
 
@@ -701,7 +533,7 @@
                         SelectionState.SELECT_ALL);
             }
             hideSuggestions();
-            getWindowAndroid().getKeyboardDelegate().hideKeyboard(mUrlBar);
+            hideKeyboard();
         }
     }
 
@@ -709,7 +541,8 @@
      * @return Whether the URL focus change is taking place, e.g. a focus animation is running on
      *         a phone device.
      */
-    protected boolean isUrlFocusChangeInProgress() {
+    @Override
+    public boolean isUrlFocusChangeInProgress() {
         return mUrlFocusChangeInProgress;
     }
 
@@ -749,7 +582,6 @@
         } else {
             mUrlFocusedFromFakebox = false;
             mUrlFocusedWithoutAnimations = false;
-            hideSuggestions();
 
             // Focus change caused by a close-tab may result in an invalid current tab.
             if (mToolbarDataProvider.hasTab()) {
@@ -791,23 +623,7 @@
             }
         }
 
-        if (mNativeInitialized) {
-            startZeroSuggest();
-        } else {
-            mDeferredNativeRunnables.add(new Runnable() {
-                @Override
-                public void run() {
-                    if (TextUtils.isEmpty(mUrlCoordinator.getTextWithAutocomplete())) {
-                        startZeroSuggest();
-                    }
-                }
-            });
-        }
-
-        if (!hasFocus) {
-            mHasStartedNewOmniboxEditSession = false;
-            mNewOmniboxEditSessionTimestamp = -1;
-        }
+        mAutocompleteCoordinator.onUrlFocusChanged(hasFocus);
     }
 
     /**
@@ -820,92 +636,18 @@
             listener.onUrlFocusChange(hasFocus);
         }
 
-        maybeShowOmniboxResultsContainer();
+        mAutocompleteCoordinator.maybeShowOmniboxResultsContainer();
         updateFadingBackgroundView(hasFocus, false);
     }
 
-    /**
-     * Make a zero suggest request if:
-     * - Native is loaded.
-     * - The URL bar has focus.
-     * - The current tab is not incognito.
-     */
-    private void startZeroSuggest() {
-        // hasWindowFocus() can return true before onWindowFocusChanged has been called, so this
-        // is an optimization, but not entirely reliable.  The underlying controller needs to also
-        // ensure we do not double trigger zero query.
-        if (!hasWindowFocus()) return;
-
-        // Reset "edited" state in the omnibox if zero suggest is triggered -- new edits
-        // now count as a new session.
-        mHasStartedNewOmniboxEditSession = false;
-        mNewOmniboxEditSessionTimestamp = -1;
-        if (mNativeInitialized && mUrlHasFocus && mToolbarDataProvider.hasTab()) {
-            mAutocomplete.startZeroSuggest(mToolbarDataProvider.getProfile(),
-                    mUrlCoordinator.getTextWithAutocomplete(), mToolbarDataProvider.getCurrentUrl(),
-                    mToolbarDataProvider.getTitle(), mUrlFocusedFromFakebox);
-        }
-    }
-
     @Override
     public void onTextChangedForAutocomplete() {
         // crbug.com/764749
         Log.w(TAG, "onTextChangedForAutocomplete");
-        cancelPendingAutocompleteStart();
 
         updateButtonVisibility();
         updateNavigationButton();
-
-        if (!mHasStartedNewOmniboxEditSession && mNativeInitialized) {
-            mAutocomplete.resetSession();
-            mHasStartedNewOmniboxEditSession = true;
-            mNewOmniboxEditSessionTimestamp = SystemClock.elapsedRealtime();
-        }
-
-        if (!isInTouchMode() && mSuggestionList != null) {
-            mSuggestionList.setSelection(0);
-        }
-
-        stopAutocomplete(false);
-        if (TextUtils.isEmpty(mUrlCoordinator.getTextWithoutAutocomplete())) {
-            // crbug.com/764749
-            Log.w(TAG, "onTextChangedForAutocomplete: url is empty");
-            hideSuggestions();
-            startZeroSuggest();
-        } else {
-            assert mRequestSuggestions == null : "Multiple omnibox requests in flight.";
-            mRequestSuggestions = new Runnable() {
-                @Override
-                public void run() {
-                    String textWithoutAutocomplete = mUrlCoordinator.getTextWithoutAutocomplete();
-                    boolean preventAutocomplete = !mUrlCoordinator.shouldAutocomplete();
-                    mRequestSuggestions = null;
-
-                    if (!mToolbarDataProvider.hasTab()) {
-                        // crbug.com/764749
-                        Log.w(TAG, "onTextChangedForAutocomplete: no tab");
-                        return;
-                    }
-
-                    Profile profile = mToolbarDataProvider.getProfile();
-                    int cursorPosition = -1;
-                    if (mUrlCoordinator.getSelectionStart() == mUrlCoordinator.getSelectionEnd()) {
-                        // Conveniently, if there is no selection, those two functions return -1,
-                        // exactly the same value needed to pass to start() to indicate no cursor
-                        // position.  Hence, there's no need to check for -1 here explicitly.
-                        cursorPosition = mUrlCoordinator.getSelectionStart();
-                    }
-                    mAutocomplete.start(profile, mToolbarDataProvider.getCurrentUrl(),
-                            textWithoutAutocomplete, cursorPosition, preventAutocomplete,
-                            mUrlFocusedFromFakebox);
-                }
-            };
-            if (mNativeInitialized) {
-                postDelayed(mRequestSuggestions, OMNIBOX_SUGGESTION_START_DELAY_MS);
-            } else {
-                mDeferredNativeRunnables.add(mRequestSuggestions);
-            }
-        }
+        mAutocompleteCoordinator.onTextChangedForAutocomplete();
     }
 
     @Override
@@ -935,6 +677,11 @@
     }
 
     @Override
+    public boolean didFocusUrlFromFakebox() {
+        return mUrlFocusedFromFakebox;
+    }
+
+    @Override
     public boolean isCurrentPage(NativePage nativePage) {
         assert nativePage != null;
         return nativePage == mToolbarDataProvider.getNewTabPageForCurrentTab();
@@ -957,7 +704,7 @@
 
         updateButtonVisibility();
 
-        mSuggestionListAdapter.setToolbarDataProvider(toolbarDataProvider);
+        mAutocompleteCoordinator.setToolbarDataProvider(toolbarDataProvider);
         mUrlCoordinator.setOnFocusChangedCallback(this::onUrlFocusChange);
     }
 
@@ -994,10 +741,10 @@
     private void updateNavigationButton() {
         @NavigationButtonType
         int type = NavigationButtonType.EMPTY;
-        if (mIsTablet && !mSuggestionItems.isEmpty()) {
+        if (mIsTablet && mAutocompleteCoordinator.getSuggestionCount() > 0) {
             // If there are suggestions showing, show the icon for the default suggestion.
             type = suggestionTypeToNavigationButtonType(
-                    mSuggestionItems.get(0).getSuggestion());
+                    mAutocompleteCoordinator.getSuggestionAt(0));
         } else if (mIsTablet) {
             type = NavigationButtonType.PAGE;
         }
@@ -1242,271 +989,6 @@
     }
 
     /**
-     * @return The suggestion list popup containing the omnibox results (or
-     *         null if it has not yet been created).
-     */
-    @VisibleForTesting
-    public OmniboxSuggestionsList getSuggestionList() {
-        return mSuggestionList;
-    }
-
-    /**
-     * Initiates the mSuggestionListPopup.  Done on demand to not slow down
-     * the initial inflation of the location bar.
-     */
-    private void initSuggestionList() {
-        // Only called from onSuggestionsReceived(), which is a callback from a listener set up by
-        // onNativeLibraryReady(), so this assert is safe.
-        assert mNativeInitialized || mShowCachedZeroSuggestResults
-                : "Trying to initialize native suggestions list before native init";
-        if (mSuggestionList != null) return;
-
-        OnLayoutChangeListener suggestionListResizer = new OnLayoutChangeListener() {
-            @Override
-            public void onLayoutChange(View v, int left, int top, int right, int bottom,
-                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                // On ICS, this update does not take affect unless it is posted to the end of the
-                // current message queue.
-                post(new Runnable() {
-                    @Override
-                    public void run() {
-                        if (mSuggestionList.isShown()) mSuggestionList.updateLayoutParams();
-                    }
-                });
-            }
-        };
-        getRootView().findViewById(R.id.control_container)
-                .addOnLayoutChangeListener(suggestionListResizer);
-
-        OmniboxSuggestionsList.OmniboxSuggestionListEmbedder embedder =
-                new OmniboxSuggestionsList.OmniboxSuggestionListEmbedder() {
-                    @Override
-                    public boolean isTablet() {
-                        return mIsTablet;
-                    }
-
-                    @Override
-                    public boolean isIncognito() {
-                        return mToolbarDataProvider.isIncognito();
-                    }
-
-                    @Override
-                    public WindowDelegate getWindowDelegate() {
-                        return mWindowDelegate;
-                    }
-
-                    @Override
-                    public BottomSheet getBottomSheet() {
-                        return mBottomSheet;
-                    }
-
-                    @Override
-                    public View getAnchorView() {
-                        return getRootView().findViewById(R.id.toolbar);
-                    }
-
-                    @Override
-                    public View getAlignmentView() {
-                        return mIsTablet ? LocationBarLayout.this : null;
-                    }
-                };
-        // TODO(tedchoc): Investigate lazily building the suggestion list off of the UI thread.
-        try (StrictModeContext unused = StrictModeContext.allowDiskReads()) {
-            mSuggestionList = new OmniboxSuggestionsList(getContext(), embedder);
-        }
-
-        // Ensure the results container is initialized and add the suggestion list to it.
-        initOmniboxResultsContainer();
-
-        // Start with visibility GONE to ensure that show() is called. http://crbug.com/517438
-        mSuggestionList.setVisibility(GONE);
-        mSuggestionList.setAdapter(mSuggestionListAdapter);
-        mSuggestionList.setClipToPadding(false);
-        mSuggestionListAdapter.setSuggestionDelegate(new OmniboxSuggestionDelegate() {
-            private long mLastActionUpTimestamp;
-
-            @Override
-            public void onSelection(OmniboxSuggestion suggestion, int position) {
-                if (mShowCachedZeroSuggestResults && !mNativeInitialized) {
-                    mDeferredOnSelection = new DeferredOnSelectionRunnable(suggestion, position) {
-                        @Override
-                        public void run() {
-                            onSelection(this.mSuggestion, this.mPosition);
-                        }
-                    };
-                    return;
-                }
-                String suggestionMatchUrl = updateSuggestionUrlIfNeeded(
-                        suggestion, position, false);
-                loadUrlFromOmniboxMatch(
-                        suggestionMatchUrl, position, suggestion, mLastActionUpTimestamp);
-                hideSuggestions();
-                getWindowAndroid().getKeyboardDelegate().hideKeyboard(mUrlBar);
-            }
-
-            @Override
-            public void onRefineSuggestion(OmniboxSuggestion suggestion) {
-                stopAutocomplete(false);
-                boolean isUrlSuggestion = suggestion.isUrlSuggestion();
-                String refineText = suggestion.getFillIntoEdit();
-                if (!isUrlSuggestion) refineText = TextUtils.concat(refineText, " ").toString();
-
-                mUrlCoordinator.setUrlBarData(UrlBarData.forNonUrlText(refineText),
-                        UrlBar.ScrollType.NO_SCROLL, UrlBarCoordinator.SelectionState.SELECT_END);
-                onTextChangedForAutocomplete();
-                if (isUrlSuggestion) {
-                    RecordUserAction.record("MobileOmniboxRefineSuggestion.Url");
-                } else {
-                    RecordUserAction.record("MobileOmniboxRefineSuggestion.Search");
-                }
-            }
-
-            @Override
-            public void onSetUrlToSuggestion(OmniboxSuggestion suggestion) {
-                if (mIgnoreOmniboxItemSelection) return;
-                setUrlBarText(UrlBarData.forNonUrlText(suggestion.getFillIntoEdit()),
-                        UrlBar.ScrollType.NO_SCROLL, SelectionState.SELECT_END);
-                mIgnoreOmniboxItemSelection = true;
-            }
-
-            @Override
-            public void onDeleteSuggestion(OmniboxSuggestion suggestion, int position) {
-                if (mAutocomplete != null) {
-                    mAutocomplete.deleteSuggestion(position, suggestion.hashCode());
-                }
-            }
-
-            @Override
-            public void onGestureDown() {
-                stopAutocomplete(false);
-            }
-
-            @Override
-            public void onGestureUp(long timestamp) {
-                mLastActionUpTimestamp = timestamp;
-            }
-
-            @Override
-            public void onShowModal() {
-                mSuggestionModalShown = true;
-            }
-
-            @Override
-            public void onHideModal() {
-                mSuggestionModalShown = false;
-            }
-
-            @Override
-            public void onTextWidthsUpdated(float requiredWidth, float matchContentsWidth) {
-                mSuggestionList.updateMaxTextWidths(requiredWidth, matchContentsWidth);
-            }
-
-            @Override
-            public float getMaxRequiredWidth() {
-                return mSuggestionList.getMaxRequiredWidth();
-            }
-
-            @Override
-            public float getMaxMatchContentsWidth() {
-                return mSuggestionList.getMaxMatchContentsWidth();
-            }
-        });
-    }
-
-    /**
-     * Handles showing/hiding the suggestions list.
-     * @param visible Whether the suggestions list should be visible.
-     */
-    protected void setSuggestionsListVisibility(final boolean visible) {
-        if (mSuggestionsShown == visible) return;
-        mSuggestionsShown = visible;
-        if (mSuggestionList != null) {
-            final boolean isShowing = mSuggestionList.isShown();
-            if (visible && !isShowing) {
-                mIgnoreOmniboxItemSelection = true; // Reset to default value.
-
-                if (mSuggestionList.getParent() == null) {
-                    mOmniboxResultsContainer.addView(mSuggestionList);
-                }
-
-                mSuggestionList.show();
-                updateSuggestionListLayoutDirection();
-            } else if (!visible && isShowing) {
-                mSuggestionList.setVisibility(GONE);
-
-                UiUtils.removeViewFromParent(mSuggestionList);
-            }
-        }
-        maybeShowOmniboxResultsContainer();
-    }
-
-    private void updateSuggestionListLayoutDirection() {
-        if (mSuggestionList == null) return;
-        int layoutDirection = ViewCompat.getLayoutDirection(this);
-        mSuggestionList.updateSuggestionsLayoutDirection(layoutDirection);
-        mSuggestionListAdapter.setLayoutDirection(layoutDirection);
-    }
-
-    /**
-     * Updates the URL we will navigate to from suggestion, if needed. This will update the search
-     * URL to be of the corpus type if query in the omnibox is displayed and update aqs= parameter
-     * on regular web search URLs.
-     *
-     * @param suggestion The chosen omnibox suggestion.
-     * @param selectedIndex The index of the chosen omnibox suggestion.
-     * @param skipCheck Whether to skip an out of bounds check.
-     * @return The url to navigate to.
-     */
-    @SuppressWarnings("ReferenceEquality")
-    private String updateSuggestionUrlIfNeeded(
-            OmniboxSuggestion suggestion, int selectedIndex, boolean skipCheck) {
-        // Only called once we have suggestions, and don't have a listener though which we can
-        // receive suggestions until the native side is ready, so this is safe
-        assert mNativeInitialized
-                : "updateSuggestionUrlIfNeeded called before native initialization";
-
-        String updatedUrl = null;
-        if (suggestion.getType() != OmniboxSuggestionType.VOICE_SUGGEST) {
-            int verifiedIndex = -1;
-            if (!skipCheck) {
-                if (mSuggestionItems.size() > selectedIndex
-                        && mSuggestionItems.get(selectedIndex).getSuggestion() == suggestion) {
-                    verifiedIndex = selectedIndex;
-                } else {
-                    // Underlying omnibox results may have changed since the selection was made,
-                    // find the suggestion item, if possible.
-                    for (int i = 0; i < mSuggestionItems.size(); i++) {
-                        if (suggestion.equals(mSuggestionItems.get(i).getSuggestion())) {
-                            verifiedIndex = i;
-                            break;
-                        }
-                    }
-                }
-            }
-
-            // If we do not have the suggestion as part of our results, skip the URL update.
-            if (verifiedIndex == -1) return suggestion.getUrl();
-
-            // TODO(mariakhomenko): Ideally we want to update match destination URL with new aqs
-            // for query in the omnibox and voice suggestions, but it's currently difficult to do.
-            long elapsedTimeSinceInputChange = mNewOmniboxEditSessionTimestamp > 0
-                    ? (SystemClock.elapsedRealtime() - mNewOmniboxEditSessionTimestamp) : -1;
-            updatedUrl = mAutocomplete.updateMatchDestinationUrlWithQueryFormulationTime(
-                    verifiedIndex, suggestion.hashCode(), elapsedTimeSinceInputChange);
-        }
-
-        return updatedUrl == null ? suggestion.getUrl() : updatedUrl;
-    }
-
-    private void clearSuggestions(boolean notifyChange) {
-        mSuggestionItems.clear();
-        // Make sure to notify the adapter. If the ListView becomes out of sync
-        // with its adapter and it has not been notified, it will throw an
-        // exception when some UI events are propagated.
-        if (notifyChange) mSuggestionListAdapter.notifyDataSetChanged();
-    }
-
-    /**
      * Hides the omnibox suggestion popup.
      *
      * <p>
@@ -1515,41 +997,43 @@
      * @see AutocompleteController#stop(boolean)
      */
     @Override
-    public void hideSuggestions() {
-        if (mAutocomplete == null || !mNativeInitialized) return;
+    public final void hideSuggestions() {
+        mAutocompleteCoordinator.hideSuggestions();
+    }
 
-        if (mShowSuggestions != null) removeCallbacks(mShowSuggestions);
-
-        stopAutocomplete(true);
-
-        setSuggestionsListVisibility(false);
-        clearSuggestions(true);
+    @Override
+    public void onSuggestionsHidden() {
         updateNavigationButton();
     }
 
-    /**
-     * Signals the autocomplete controller to stop generating omnibox suggestions and cancels the
-     * queued task to start the autocomplete controller, if any.
-     *
-     * @param clear Whether to clear the most recent autocomplete results.
-     */
-    private void stopAutocomplete(boolean clear) {
-        if (mAutocomplete != null) mAutocomplete.stop(clear);
-        cancelPendingAutocompleteStart();
+    @Override
+    public void hideKeyboard() {
+        getWindowAndroid().getKeyboardDelegate().hideKeyboard(mUrlBar);
     }
 
-    /**
-     * Cancels the queued task to start the autocomplete controller, if any.
-     */
-    @VisibleForTesting
-    void cancelPendingAutocompleteStart() {
-        if (mRequestSuggestions != null) {
-            // There is a request for suggestions either waiting for the native side
-            // to start, or on the message queue. Remove it from wherever it is.
-            if (!mDeferredNativeRunnables.remove(mRequestSuggestions)) {
-                removeCallbacks(mRequestSuggestions);
-            }
-            mRequestSuggestions = null;
+    @Override
+    public void onSuggestionsChanged(String autocompleteText) {
+        String userText = mUrlCoordinator.getTextWithoutAutocomplete();
+        if (mUrlCoordinator.shouldAutocomplete()) {
+            mUrlCoordinator.setAutocompleteText(userText, autocompleteText);
+        }
+
+        // Handle the case where suggestions (in particular zero suggest) are received without the
+        // URL focusing happening.
+        if (mUrlFocusedWithoutAnimations && mUrlHasFocus) {
+            handleUrlFocusAnimation(mUrlHasFocus);
+        }
+
+        // Update the navigation button to show the default suggestion's icon.
+        updateNavigationButton();
+
+        if (mNativeInitialized
+                && !CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_INSTANT)
+                && PrivacyPreferencesManager.getInstance().shouldPrerender()
+                && mToolbarDataProvider.hasTab()) {
+            mOmniboxPrerender.prerenderMaybe(userText, getOriginalUrl(),
+                    mAutocompleteCoordinator.getCurrentNativeAutocompleteResult(),
+                    mToolbarDataProvider.getProfile(), mToolbarDataProvider.getTab());
         }
     }
 
@@ -1602,11 +1086,7 @@
         setUrlBarText(UrlBarData.forNonUrlText(query), UrlBar.ScrollType.NO_SCROLL,
                 SelectionState.SELECT_ALL);
         setUrlBarFocus(true);
-        stopAutocomplete(false);
-        if (mToolbarDataProvider.hasTab()) {
-            mAutocomplete.start(mToolbarDataProvider.getProfile(),
-                    mToolbarDataProvider.getCurrentUrl(), query, -1, false, false);
-        }
+        mAutocompleteCoordinator.startAutocompleteForQuery(query);
         post(new Runnable() {
             @Override
             public void run() {
@@ -1632,7 +1112,7 @@
                 updateButtonVisibility();
             }
 
-            startZeroSuggest();
+            mAutocompleteCoordinator.startZeroSuggest();
             RecordUserAction.record("MobileOmniboxDeleteUrl");
             return;
         } else if (!mUrlHasFocus && shouldShowPageInfoForView(v)) {
@@ -1652,119 +1132,10 @@
     }
 
     @Override
-    public void onSuggestionsReceived(List<OmniboxSuggestion> newSuggestions,
-            String inlineAutocompleteText) {
-        // This is a callback from a listener that is set up by onNativeLibraryReady,
-        // so can only be called once the native side is set up unless we are showing
-        // cached java-only suggestions.
-        assert mNativeInitialized || mShowCachedZeroSuggestResults
-                : "Native suggestions received before native side intialialized";
-
-        if (mDeferredOnSelection != null) {
-            mDeferredOnSelection.setShouldLog(newSuggestions.size() > mDeferredOnSelection.mPosition
-                    && mDeferredOnSelection.mSuggestion.equals(
-                            newSuggestions.get(mDeferredOnSelection.mPosition)));
-            mDeferredOnSelection.run();
-            mDeferredOnSelection = null;
-        }
-        String userText = mUrlCoordinator.getTextWithoutAutocomplete();
-        mUrlTextAfterSuggestionsReceived = userText + inlineAutocompleteText;
-
-        boolean itemsChanged = false;
-        boolean itemCountChanged = false;
-        // If the length of the incoming suggestions matches that of those currently being shown,
-        // replace them inline to allow transient entries to retain their proper highlighting.
-        if (mSuggestionItems.size() == newSuggestions.size()) {
-            for (int index = 0; index < newSuggestions.size(); index++) {
-                OmniboxResultItem suggestionItem = mSuggestionItems.get(index);
-                OmniboxSuggestion suggestion = suggestionItem.getSuggestion();
-                OmniboxSuggestion newSuggestion = newSuggestions.get(index);
-                // Determine whether the suggestions have changed. If not, save some time by not
-                // redrawing the suggestions UI.
-                if (suggestion.equals(newSuggestion)
-                        && suggestion.getType() != OmniboxSuggestionType.SEARCH_SUGGEST_TAIL) {
-                    if (suggestionItem.getMatchedQuery().equals(userText)) {
-                        continue;
-                    } else if (!suggestion.getDisplayText().startsWith(userText)
-                            && !suggestion.getUrl().contains(userText)) {
-                        continue;
-                    }
-                }
-                mSuggestionItems.set(index, new OmniboxResultItem(newSuggestion, userText));
-                itemsChanged = true;
-            }
-        } else {
-            itemsChanged = true;
-            itemCountChanged = true;
-            clearSuggestions(false);
-            for (int i = 0; i < newSuggestions.size(); i++) {
-                mSuggestionItems.add(new OmniboxResultItem(newSuggestions.get(i), userText));
-            }
-        }
-
-        if (mSuggestionItems.isEmpty()) {
-            if (mSuggestionsShown) {
-                hideSuggestions();
-            } else {
-                mSuggestionListAdapter.notifySuggestionsChanged();
-            }
-            return;
-        }
-
-        if (mUrlCoordinator.shouldAutocomplete()) {
-            mUrlCoordinator.setAutocompleteText(userText, inlineAutocompleteText);
-        }
-
-        // Show the suggestion list.
-        initSuggestionList();  // It may not have been initialized yet.
-        mSuggestionList.resetMaxTextWidths();
-
-        // Handle the case where suggestions (in particular zero suggest) are received without the
-        // URL focusing happening.
-        if (mUrlFocusedWithoutAnimations && mUrlHasFocus) {
-            handleUrlFocusAnimation(mUrlHasFocus);
-        }
-
-        if (itemsChanged) mSuggestionListAdapter.notifySuggestionsChanged();
-
-        if (mUrlBar.hasFocus()) {
-            final boolean updateLayoutParams = itemCountChanged || mShowSuggestions != null;
-            if (mShowSuggestions != null) removeCallbacks(mShowSuggestions);
-            mShowSuggestions = new Runnable() {
-                @Override
-                public void run() {
-                    setSuggestionsListVisibility(true);
-                    if (updateLayoutParams) {
-                        mSuggestionList.updateLayoutParams();
-                    }
-                    mShowSuggestions = null;
-                }
-            };
-            if (!isUrlFocusChangeInProgress()) {
-                mShowSuggestions.run();
-            } else {
-                postDelayed(mShowSuggestions, ToolbarPhone.URL_FOCUS_CHANGE_ANIMATION_DURATION_MS);
-            }
-        }
-
-        // Update the navigation button to show the default suggestion's icon.
-        updateNavigationButton();
-
-        if (mNativeInitialized
-                && !CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_INSTANT)
-                && PrivacyPreferencesManager.getInstance().shouldPrerender()
-                && mToolbarDataProvider.hasTab()) {
-            mOmniboxPrerender.prerenderMaybe(userText, getOriginalUrl(),
-                    mAutocomplete.getCurrentNativeAutocompleteResult(),
-                    mToolbarDataProvider.getProfile(), getCurrentTab());
-        }
-    }
-
-    @Override
     public void backKeyPressed() {
         setUrlBarFocus(false);
         hideSuggestions();
-        getWindowAndroid().getKeyboardDelegate().hideKeyboard(mUrlBar);
+        hideKeyboard();
         // Revert the URL to match the current page.
         setUrlToPageUrl();
         focusCurrentTab();
@@ -1851,50 +1222,10 @@
                 UrlBarData.EMPTY, UrlBar.ScrollType.SCROLL_TO_BEGINNING, SelectionState.SELECT_ALL);
     }
 
-    private void loadUrlFromOmniboxMatch(
-            String url, int matchPosition, OmniboxSuggestion suggestion, long inputStart) {
-        // loadUrl modifies AutocompleteController's state clearing the native
-        // AutocompleteResults needed by onSuggestionsSelected. Therefore,
-        // loadUrl should should be invoked last.
-        int transition = suggestion.getTransition();
-        int type = suggestion.getType();
-        String currentPageUrl = mToolbarDataProvider.getCurrentUrl();
-        WebContents webContents =
-                mToolbarDataProvider.hasTab() ? getCurrentTab().getWebContents() : null;
-        long elapsedTimeSinceModified = mNewOmniboxEditSessionTimestamp > 0
-                ? (SystemClock.elapsedRealtime() - mNewOmniboxEditSessionTimestamp) : -1;
-        boolean shouldSkipNativeLog = mShowCachedZeroSuggestResults
-                && (mDeferredOnSelection != null)
-                && !mDeferredOnSelection.shouldLog();
-        if (!shouldSkipNativeLog) {
-            int autocompleteLength = mUrlCoordinator.getTextWithAutocomplete().length()
-                    - mUrlCoordinator.getTextWithoutAutocomplete().length();
-            mAutocomplete.onSuggestionSelected(matchPosition, suggestion.hashCode(), type,
-                    currentPageUrl, mUrlFocusedFromFakebox, elapsedTimeSinceModified,
-                    autocompleteLength, webContents);
-        }
-        if (((transition & PageTransition.CORE_MASK) == PageTransition.TYPED)
-                && TextUtils.equals(url, mToolbarDataProvider.getCurrentUrl())) {
-            // When the user hit enter on the existing permanent URL, treat it like a
-            // reload for scoring purposes.  We could detect this by just checking
-            // user_input_in_progress_, but it seems better to treat "edits" that end
-            // up leaving the URL unchanged (e.g. deleting the last character and then
-            // retyping it) as reloads too.  We exclude non-TYPED transitions because if
-            // the transition is GENERATED, the user input something that looked
-            // different from the current URL, even if it wound up at the same place
-            // (e.g. manually retyping the same search query), and it seems wrong to
-            // treat this as a reload.
-            transition = PageTransition.RELOAD;
-        } else if (type == OmniboxSuggestionType.URL_WHAT_YOU_TYPED
-                && mUrlCoordinator.wasLastEditPaste()) {
-            // It's important to use the page transition from the suggestion or we might end
-            // up saving generated URLs as typed URLs, which would then pollute the subsequent
-            // omnibox results. There is one special case where the suggestion text was pasted,
-            // where we want the transition type to be LINK.
-
-            transition = PageTransition.LINK;
-        }
-        loadUrl(url, transition, inputStart);
+    @Override
+    public void setOmniboxEditingText(String text) {
+        mUrlCoordinator.setUrlBarData(UrlBarData.forNonUrlText(text), UrlBar.ScrollType.NO_SCROLL,
+                UrlBarCoordinator.SelectionState.SELECT_END);
     }
 
     @Override
@@ -1906,7 +1237,8 @@
      * Load the url given with the given transition. Exposed for child classes to overwrite as
      * necessary.
      */
-    protected void loadUrl(String url, int transition, long inputStart) {
+    @Override
+    public void loadUrl(String url, @PageTransition int transition, long inputStart) {
         Tab currentTab = getCurrentTab();
 
         // The code of the rest of this class ensures that this can't be called until the native
@@ -1945,7 +1277,7 @@
         focusCurrentTab();
         // Prevent any upcoming omnibox suggestions from showing. We have to do this after we load
         // the URL as this will hide the suggestions and trigger a cancel of the prerendered page.
-        stopAutocomplete(true);
+        mAutocompleteCoordinator.stopAutocomplete(true);
     }
 
     /**
@@ -1979,37 +1311,6 @@
         return !mToolbarDataProvider.isIncognito();
     }
 
-    private void initOmniboxResultsContainer() {
-        if (mOmniboxResultsContainer != null) return;
-
-        ViewStub overlayStub =
-                (ViewStub) getRootView().findViewById(R.id.omnibox_results_container_stub);
-        mOmniboxResultsContainer = (ViewGroup) overlayStub.inflate();
-
-        int topMargin = getResources().getDimensionPixelSize(R.dimen.tab_strip_height);
-        mScrimParams = new ScrimParams(mOmniboxResultsContainer, false, false, topMargin, this);
-    }
-
-    private void maybeShowOmniboxResultsContainer() {
-        if (mSuggestionsShown || mUrlHasFocus) {
-            initOmniboxResultsContainer();
-            updateOmniboxResultsContainerVisibility(true);
-        }
-    }
-
-    private void updateOmniboxResultsContainerVisibility(boolean visible) {
-        if (mOmniboxResultsContainer == null) return;
-
-        boolean currentlyVisible = mOmniboxResultsContainer.getVisibility() == VISIBLE;
-        if (currentlyVisible == visible) return;
-
-        if (visible) {
-            mOmniboxResultsContainer.setVisibility(VISIBLE);
-        } else {
-            mOmniboxResultsContainer.setVisibility(INVISIBLE);
-        }
-    }
-
     @Override
     public void onScrimClick() {
         setUrlBarFocus(false);
@@ -2026,7 +1327,7 @@
             chromeActivity.addViewObscuringAllTabs(mScrim);
         } else {
             chromeActivity.removeViewObscuringAllTabs(mScrim);
-            updateOmniboxResultsContainerVisibility(false);
+            mAutocompleteCoordinator.updateOmniboxResultsContainerVisibility(false);
         }
     }
 
@@ -2048,11 +1349,19 @@
      *                        scrim.
      */
     protected void updateFadingBackgroundView(boolean visible, boolean ignoreNtpChecks) {
-        if (mScrim == null || mScrimParams == null) return;
+        if (mScrim == null) return;
         NewTabPage ntp = mToolbarDataProvider.getNewTabPageForCurrentTab();
         boolean locationBarShownInNTP = ntp != null && ntp.isLocationBarShownInNTP();
 
         if (visible && (!locationBarShownInNTP || ignoreNtpChecks)) {
+            if (mScrimParams == null) {
+                int topMargin = getResources().getDimensionPixelSize(R.dimen.tab_strip_height);
+                View omniboxSuggestionsContainer =
+                        mAutocompleteCoordinator.getSuggestionContainerView();
+                if (omniboxSuggestionsContainer == null) return;
+                mScrimParams =
+                        new ScrimParams(omniboxSuggestionsContainer, false, false, topMargin, this);
+            }
             mScrimParams.backgroundColor =
                     !mIsTablet && !mToolbarDataProvider.isIncognito() ? mLightScrimColor : null;
 
@@ -2067,14 +1376,14 @@
     @Override
     public void onWindowFocusChanged(boolean hasWindowFocus) {
         super.onWindowFocusChanged(hasWindowFocus);
-        if (!hasWindowFocus && !mSuggestionModalShown) {
+        if (!hasWindowFocus && !mAutocompleteCoordinator.isSuggestionModalShown()) {
             hideSuggestions();
         } else if (hasWindowFocus && mUrlHasFocus && mNativeInitialized) {
             String currentUrlBarText = mUrlCoordinator.getTextWithAutocomplete();
             if (TextUtils.isEmpty(currentUrlBarText)
                     || TextUtils.equals(currentUrlBarText,
                                mToolbarDataProvider.getUrlBarData().getEditingOrDisplayText())) {
-                startZeroSuggest();
+                mAutocompleteCoordinator.startZeroSuggest();
             } else {
                 onTextChangedForAutocomplete();
             }
@@ -2136,10 +1445,7 @@
             setUrlToPageUrl();
         }
 
-        if (mSuggestionList != null) {
-            mSuggestionList.refreshPopupBackground();
-        }
-        mSuggestionListAdapter.setUseDarkColors(mUseDarkColors);
+        mAutocompleteCoordinator.updateVisualsForState(mUseDarkColors);
     }
 
     /**
@@ -2185,11 +1491,6 @@
     public void setShowTitle(boolean showTitle) { }
 
     @Override
-    public AutocompleteController getAutocompleteController() {
-        return mAutocomplete;
-    }
-
-    @Override
     public WindowAndroid getWindowAndroid() {
         return mWindowAndroid;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
index 255c0c7..44276d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -149,11 +149,6 @@
                 setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN, false);
             }
             getWindowAndroid().getKeyboardDelegate().showKeyboard(mUrlBar);
-            // As the position of the navigation icon has changed, ensure the suggestions are
-            // updated to reflect the new position.
-            if (getSuggestionList() != null && getSuggestionList().isShown()) {
-                getSuggestionList().invalidateSuggestionViews();
-            }
         }
         setUrlFocusChangeInProgress(false);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandler.java
index 68ce980..93e8f49f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandler.java
@@ -107,11 +107,14 @@
         ToolbarDataProvider getToolbarDataProvider();
 
         /**
-         * Grabs a reference to the autocomplete controller from the location bar.
-         * @return The {@link AutocompleteController} currently in use by the
+         * Grabs a reference to the autocomplete coordinator from the location bar.
+         * @return The {@link AutocompleteCoordinator} currently in use by the
          *         {@link LocationBarLayout}.
          */
-        AutocompleteController getAutocompleteController();
+        // TODO(tedchoc): Limit the visibility of what is passed in here.  This does not need the
+        //                full coordinator.  It simply needs a way to pass voice suggestions to the
+        //                AutocompleteController.
+        AutocompleteCoordinator getAutocompleteCoordinator();
 
         /**
          * @return The current {@link WindowAndroid}.
@@ -185,12 +188,13 @@
                 return;
             }
 
-            AutocompleteController autocompleteController = mDelegate.getAutocompleteController();
-            assert autocompleteController != null;
+            AutocompleteCoordinator autocompleteCoordinator =
+                    mDelegate.getAutocompleteCoordinator();
+            assert autocompleteCoordinator != null;
 
             recordVoiceSearchFinishEventSource(mSource);
 
-            VoiceResult topResult = autocompleteController.onVoiceResults(data.getExtras());
+            VoiceResult topResult = autocompleteCoordinator.onVoiceResults(data.getExtras());
             if (topResult == null) {
                 recordVoiceSearchResult(false);
                 return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
index 35ae34d..e820f90 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -694,20 +694,43 @@
         Editable url = getText();
         int measuredWidth = getMeasuredWidth() - (getPaddingLeft() + getPaddingRight());
 
+        Layout textLayout = getLayout();
         assert getLayout().getLineCount() == 1;
-        float endPointX = getLayout().getPrimaryHorizontal(mOriginEndIndex);
-        // Using 1 instead of 0 as zero does not return a valid value in RTL (always returns 0
-        // instead of the valid scroll position).
-        float startPointX = url.length() == 1 ? 0 : getLayout().getPrimaryHorizontal(1);
+        final int originEndIndex = mOriginEndIndex;
+        float endPointX = textLayout.getPrimaryHorizontal(originEndIndex);
+        // Compare the position offset of the last character and the character prior to determine
+        // the LTR-ness of the final component of the URL.
+        float priorToEndPointX = url.length() == 1
+                ? 0
+                : textLayout.getPrimaryHorizontal(Math.max(0, originEndIndex - 1));
 
         float scrollPos;
-        if (startPointX < endPointX) {
+        if (priorToEndPointX < endPointX) {
             // LTR
             scrollPos = Math.max(0, endPointX - measuredWidth);
         } else {
             // RTL
-            float width = getLayout().getPaint().measureText(
-                    url.subSequence(0, mOriginEndIndex).toString());
+
+            // To handle BiDirectional text, search backward from the two existing offsets to find
+            // the first LTR character.  Ensure the final RTL component of the domain is visible
+            // above any of the prior LTR pieces.
+            int rtlStartIndexForEndingRun = originEndIndex - 1;
+            for (int i = originEndIndex - 2; i >= 0; i--) {
+                float indexOffsetDrawPosition = textLayout.getPrimaryHorizontal(i);
+                if (indexOffsetDrawPosition > endPointX) {
+                    rtlStartIndexForEndingRun = i;
+                } else {
+                    // getPrimaryHorizontal determines the index position for the next character
+                    // based on the previous characters.  In bi-directional text, the first RTL
+                    // character following LTR text will have an LTR-appearing horizontal offset
+                    // as it is based on the preceding LTR text.  Thus, the start of the RTL
+                    // character run will be after and including the first LTR horizontal index.
+                    rtlStartIndexForEndingRun = Math.max(0, rtlStartIndexForEndingRun - 1);
+                    break;
+                }
+            }
+            float width = textLayout.getPaint().measureText(
+                    url.subSequence(rtlStartIndexForEndingRun, originEndIndex).toString());
             if (width < measuredWidth) {
                 scrollPos = Math.max(0, endPointX + width - measuredWidth);
             } else {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java
index a98e505d..96ff63dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java
@@ -21,7 +21,7 @@
 /**
  * Coordinates the interactions with the UrlBar text component.
  */
-public class UrlBarCoordinator {
+public class UrlBarCoordinator implements UrlBarEditingTextStateProvider {
     /** Specified how the text should be selected when focused. */
     @IntDef({SelectionState.SELECT_ALL, SelectionState.SELECT_END})
     @Retention(RetentionPolicy.SOURCE)
@@ -99,32 +99,32 @@
         mUrlBar.selectAll();
     }
 
-    /** Return the starting selection index for the text. */
+    @Override
     public int getSelectionStart() {
         return mUrlBar.getSelectionStart();
     }
 
-    /** Return the ending selection index for the text. */
+    @Override
     public int getSelectionEnd() {
         return mUrlBar.getSelectionEnd();
     }
 
-    /** Return whether the view can accept autocomplete. */
+    @Override
     public boolean shouldAutocomplete() {
         return mUrlBar.shouldAutocomplete();
     }
 
-    /** Return whether the last edit was the result of a paste operation. */
+    @Override
     public boolean wasLastEditPaste() {
         return mUrlBar.wasLastEditPaste();
     }
 
-    /** Return the full text with any inline autocomplete. */
+    @Override
     public String getTextWithAutocomplete() {
         return mUrlBar.getTextWithAutocomplete();
     }
 
-    /** Return the text excluding any inline autocomplete. */
+    @Override
     public String getTextWithoutAutocomplete() {
         return mUrlBar.getTextWithoutAutocomplete();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarEditingTextStateProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarEditingTextStateProvider.java
new file mode 100644
index 0000000..0d592f8
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarEditingTextStateProvider.java
@@ -0,0 +1,28 @@
+// 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.omnibox;
+
+/**
+ * Provider of editing text state from the UrlBar/Omnibox.
+ */
+public interface UrlBarEditingTextStateProvider {
+    /** Return the starting selection index for the text. */
+    public int getSelectionStart();
+
+    /** Return the ending selection index for the text. */
+    public int getSelectionEnd();
+
+    /** Return whether the view can accept autocomplete. */
+    public boolean shouldAutocomplete();
+
+    /** Return whether the last edit was the result of a paste operation. */
+    public boolean wasLastEditPaste();
+
+    /** Return the full text with any inline autocomplete. */
+    public String getTextWithAutocomplete();
+
+    /** Return the text excluding any inline autocomplete. */
+    public String getTextWithoutAutocomplete();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java
index b62c791..2189ac7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java
@@ -101,17 +101,18 @@
 
         // Add 'Add credit card' button. Tap of it brings up card editor which allows users type in
         // new credit cards.
-        Preference add_card_pref = new Preference(getActivity());
-        Drawable plusIcon = ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.plus);
-        plusIcon.mutate();
-        plusIcon.setColorFilter(
-                ApiCompatibilityUtils.getColor(getResources(), R.color.pref_accent_color),
-                PorterDuff.Mode.SRC_IN);
-        add_card_pref.setIcon(plusIcon);
-        add_card_pref.setTitle(R.string.autofill_create_credit_card);
-        add_card_pref.setFragment(AutofillLocalCardEditor.class.getName());
-        add_card_pref.setEnabled(PersonalDataManager.isAutofillCreditCardEnabled());
-        getPreferenceScreen().addPreference(add_card_pref);
+        if (PersonalDataManager.isAutofillCreditCardEnabled()) {
+            Preference add_card_pref = new Preference(getActivity());
+            Drawable plusIcon = ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.plus);
+            plusIcon.mutate();
+            plusIcon.setColorFilter(
+                    ApiCompatibilityUtils.getColor(getResources(), R.color.pref_accent_color),
+                    PorterDuff.Mode.SRC_IN);
+            add_card_pref.setIcon(plusIcon);
+            add_card_pref.setTitle(R.string.autofill_create_credit_card);
+            add_card_pref.setFragment(AutofillLocalCardEditor.class.getName());
+            getPreferenceScreen().addPreference(add_card_pref);
+        }
 
         // Add the link to payment apps only after the credit card list is rebuilt.
         if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_PAYMENT_APPS)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragment.java
index 2725dae..d8383de 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillProfilesFragment.java
@@ -102,20 +102,21 @@
 
         // Add 'Add address' button. Tap of it brings up address editor which allows users type in
         // new addresses.
-        AutofillProfileEditorPreference pref =
-                new AutofillProfileEditorPreference(getActivity(), sObserverForTest);
-        Drawable plusIcon = ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.plus);
-        plusIcon.mutate();
-        plusIcon.setColorFilter(
-                ApiCompatibilityUtils.getColor(getResources(), R.color.pref_accent_color),
-                PorterDuff.Mode.SRC_IN);
-        pref.setIcon(plusIcon);
-        pref.setTitle(R.string.autofill_create_profile);
-        pref.setKey(PREF_NEW_PROFILE); // For testing.
-        pref.setEnabled(PersonalDataManager.isAutofillProfileEnabled());
+        if (PersonalDataManager.isAutofillProfileEnabled()) {
+            AutofillProfileEditorPreference pref =
+                    new AutofillProfileEditorPreference(getActivity(), sObserverForTest);
+            Drawable plusIcon = ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.plus);
+            plusIcon.mutate();
+            plusIcon.setColorFilter(
+                    ApiCompatibilityUtils.getColor(getResources(), R.color.pref_accent_color),
+                    PorterDuff.Mode.SRC_IN);
+            pref.setIcon(plusIcon);
+            pref.setTitle(R.string.autofill_create_profile);
+            pref.setKey(PREF_NEW_PROFILE); // For testing.
 
-        try (StrictModeContext unused = StrictModeContext.allowDiskWrites()) {
-            getPreferenceScreen().addPreference(pref);
+            try (StrictModeContext unused = StrictModeContext.allowDiskWrites()) {
+                getPreferenceScreen().addPreference(pref);
+            }
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index 8e62d8a3..4a805d87 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -135,7 +135,7 @@
 
         // Kick off everything needed for the user to type into the box.
         beginQuery();
-        mSearchBox.showCachedZeroSuggestResultsIfAvailable();
+        mSearchBox.getAutocompleteCoordinator().showCachedZeroSuggestResultsIfAvailable();
 
         // Kick off loading of the native library.
         if (!getActivityDelegate().shouldDelayNativeInitialization()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
index 60fc3467..b27ac35 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
@@ -15,15 +15,12 @@
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.omnibox.LocationBarLayout;
 import org.chromium.chrome.browser.omnibox.LocationBarVoiceRecognitionHandler;
-import org.chromium.chrome.browser.omnibox.OmniboxSuggestion;
 import org.chromium.chrome.browser.omnibox.UrlBar;
 import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.toolbar.ToolbarPhone;
 
-import java.util.List;
-
 /** Implementation of the {@link LocationBarLayout} that is displayed for widget searches. */
 public class SearchActivityLocationBarLayout extends LocationBarLayout {
     /** Delegates calls out to the containing Activity. */
@@ -45,6 +42,8 @@
         setBackground(ToolbarPhone.createModernLocationBarBackground(getResources()));
 
         mPendingSearchPromoDecision = LocaleManager.getInstance().needToCheckForSearchEnginePromo();
+        getAutocompleteCoordinator().setShouldPreventOmniboxAutocomplete(
+                mPendingSearchPromoDecision);
     }
 
     /** Set the {@link Delegate}. */
@@ -53,7 +52,7 @@
     }
 
     @Override
-    protected void loadUrl(String url, int transition, long inputStart) {
+    public void loadUrl(String url, int transition, long inputStart) {
         mDelegate.loadUrl(url);
         LocaleManager.getInstance().recordLocaleBasedSearchMetrics(true, url, transition);
     }
@@ -74,13 +73,8 @@
         setAutocompleteProfile(Profile.getLastUsedProfile().getOriginalProfile());
 
         mPendingSearchPromoDecision = LocaleManager.getInstance().needToCheckForSearchEnginePromo();
-    }
-
-    @Override
-    public void onSuggestionsReceived(
-            List<OmniboxSuggestion> newSuggestions, String inlineAutocompleteText) {
-        if (mPendingSearchPromoDecision) return;
-        super.onSuggestionsReceived(newSuggestions, inlineAutocompleteText);
+        getAutocompleteCoordinator().setShouldPreventOmniboxAutocomplete(
+                mPendingSearchPromoDecision);
     }
 
     /** Called when the SearchActivity has finished initialization. */
@@ -90,12 +84,14 @@
                     mVoiceRecognitionHandler.isVoiceSearchEnabled());
         }
         if (isVoiceSearchIntent && mUrlBar.isFocused()) onUrlFocusChange(true);
-        if (!TextUtils.isEmpty(mUrlCoordinator.getTextWithAutocomplete())) {
-            onTextChangedForAutocomplete();
-        }
 
         assert !LocaleManager.getInstance().needToCheckForSearchEnginePromo();
         mPendingSearchPromoDecision = false;
+        getAutocompleteCoordinator().setShouldPreventOmniboxAutocomplete(
+                mPendingSearchPromoDecision);
+        if (!TextUtils.isEmpty(mUrlCoordinator.getTextWithAutocomplete())) {
+            onTextChangedForAutocomplete();
+        }
 
         if (mPendingBeginQuery) {
             beginQueryInternal(isVoiceSearchIntent);
@@ -148,7 +144,7 @@
     //                is finalized after native has been initialized.
     private void focusTextBox() {
         if (!mUrlBar.hasFocus()) mUrlBar.requestFocus();
-        setShowCachedZeroSuggestResults(true);
+        getAutocompleteCoordinator().setShowCachedZeroSuggestResults(true);
 
         new Handler().post(new Runnable() {
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
index 8a8a6b8..1c7220dd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java
@@ -113,6 +113,11 @@
             public void onCrash(Tab tab, boolean sadTabShown) {
                 clearRequestsAndHide();
             }
+
+            @Override
+            public void onDestroyed(Tab tab) {
+                if (mLastActivityTab == tab) mLastActivityTab = null;
+            }
         };
 
         mTabProvider.addObserverAndTrigger(new HintlessActivityTabObserver() {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 9a7a278..356d9e2 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1304,12 +1304,6 @@
       <message name="IDS_DATA_REDUCTION_USAGE_RESET_STATISTICS_CONFIRMATION_BUTTON" desc="Text to be displayed on the confirmation button to proceed with resetting the Data Reduction statistics.">
         Reset
       </message>
-      <message name="IDS_SAFE_BROWSING_DESCRIPTION" desc="Description text for safe browsing">
-        Chrome’s Safe Browsing system will also be used to detect malicious pages and protect you from phishing, malware, and harmful downloads.
-      </message>
-      <message name="IDS_DATA_REDUCTION_CAVEATS_DESCRIPTION" desc="Description text for usage caveats">
-        This feature may interfere with access to premium data services provided by your carrier.
-      </message>
 
       <!-- Data Saver Promo and FRE card -->
       <message name="IDS_DATA_REDUCTION_PROMO_TITLE" desc="The title for the promo inviting users to enable Data Saver" >
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 6ab6b0b0..8341b54 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -517,21 +517,21 @@
   "java/src/org/chromium/chrome/browser/download/home/list/holder/DateViewHolder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/holder/GenericViewHolder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/holder/ImageViewHolder.java",
+  "java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressImageViewHolder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressVideoViewHolder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressViewHolder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/holder/ListItemViewHolder.java",
-  "java/src/org/chromium/chrome/browser/download/home/list/holder/MoreButtonViewHolder.java",
+  "java/src/org/chromium/chrome/browser/download/home/list/holder/OfflineItemViewHolder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/holder/PrefetchViewHolder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/holder/SectionTitleViewHolder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/holder/SeparatorViewHolder.java",
-  "java/src/org/chromium/chrome/browser/download/home/list/holder/ThumbnailAwareViewHolder.java",
   "java/src/org/chromium/chrome/browser/download/home/list/holder/VideoViewHolder.java",
+  "java/src/org/chromium/chrome/browser/download/home/list/view/AspectRatioFrameLayout.java",
   "java/src/org/chromium/chrome/browser/download/home/list/view/AsyncImageView.java",
   "java/src/org/chromium/chrome/browser/download/home/list/view/AutoAnimatorDrawable.java",
   "java/src/org/chromium/chrome/browser/download/home/list/view/CircularProgressView.java",
   "java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundDrawableCompat.java",
   "java/src/org/chromium/chrome/browser/download/home/list/view/ForegroundRoundedCornerImageView.java",
-  "java/src/org/chromium/chrome/browser/download/home/list/view/SquareAsyncImageView.java",
   "java/src/org/chromium/chrome/browser/download/home/list/view/UiUtils.java",
   "java/src/org/chromium/chrome/browser/download/home/list/ListProperties.java",
   "java/src/org/chromium/chrome/browser/download/home/list/ListPropertyViewBinder.java",
@@ -1037,6 +1037,7 @@
   "java/src/org/chromium/chrome/browser/omnibox/AnswerTextBuilder.java",
   "java/src/org/chromium/chrome/browser/omnibox/AnswersImage.java",
   "java/src/org/chromium/chrome/browser/omnibox/AutocompleteController.java",
+  "java/src/org/chromium/chrome/browser/omnibox/AutocompleteCoordinator.java",
   "java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditText.java",
   "java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModel.java",
   "java/src/org/chromium/chrome/browser/omnibox/AutocompleteEditTextModelBase.java",
@@ -1060,6 +1061,7 @@
   "java/src/org/chromium/chrome/browser/omnibox/UrlBar.java",
   "java/src/org/chromium/chrome/browser/omnibox/UrlBarCoordinator.java",
   "java/src/org/chromium/chrome/browser/omnibox/UrlBarData.java",
+  "java/src/org/chromium/chrome/browser/omnibox/UrlBarEditingTextStateProvider.java",
   "java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java",
   "java/src/org/chromium/chrome/browser/omnibox/UrlBarProperties.java",
   "java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
index f08dd36..d18a8d85 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
@@ -30,7 +30,6 @@
 import org.chromium.chrome.browser.download.DownloadManagerServiceTest.MockDownloadNotifier.MethodID;
 import org.chromium.chrome.browser.test.ChromeBrowserTestRule;
 import org.chromium.components.offline_items_collection.ContentId;
-import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
 import org.chromium.components.offline_items_collection.OfflineItemProgressUnit;
 import org.chromium.components.offline_items_collection.PendingState;
@@ -141,7 +140,7 @@
         }
 
         @Override
-        public void notifyDownloadFailed(DownloadInfo downloadInfo, @FailState int failState) {
+        public void notifyDownloadFailed(DownloadInfo downloadInfo) {
             assertCorrectExpectedCall(MethodID.DOWNLOAD_FAILED, downloadInfo, true);
 
         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
index 2072176..7f4fab6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -30,6 +30,7 @@
 import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory;
 import org.chromium.components.background_task_scheduler.TaskInfo;
 import org.chromium.components.offline_items_collection.ContentId;
+import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.LegacyHelpers;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
 import org.chromium.components.offline_items_collection.OfflineItemProgressUnit;
@@ -343,7 +344,7 @@
         Assert.assertEquals(2, entries.size());
 
         ContentId id2 = LegacyHelpers.buildLegacyContentId(false, guid2);
-        service.notifyDownloadFailed(id2, "failed", null);
+        service.notifyDownloadFailed(id2, "failed", null, FailState.CANNOT_DOWNLOAD);
         entries = DownloadManagerService.getStoredDownloadInfo(
                 sharedPrefs, DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS);
         Assert.assertEquals(1, entries.size());
@@ -497,7 +498,7 @@
         service.notifyDownloadProgress(id, "/path/to/test", Progress.createIndeterminateProgress(),
                 10L, 1000L, 10L, false, false, false, null);
         Assert.assertFalse(service.hideSummaryNotificationIfNecessary(-1));
-        service.notifyDownloadFailed(id, "/path/to/test", null);
+        service.notifyDownloadFailed(id, "/path/to/test", null, FailState.CANNOT_DOWNLOAD);
         Assert.assertTrue(service.hideSummaryNotificationIfNecessary(-1));
     }
 
@@ -607,7 +608,7 @@
         service.notifyDownloadProgress(id, "/path/to/test", Progress.createIndeterminateProgress(),
                 10L, 1000L, 10L, false, false, false, null);
         Assert.assertTrue(getService().isForegroundRunning());
-        service.notifyDownloadFailed(id, "/path/to/test", null);
+        service.notifyDownloadFailed(id, "/path/to/test", null, FailState.CANNOT_DOWNLOAD);
         Assert.assertFalse(getService().isForegroundRunning());
 
         // In the case of offline pages failures, cancel is called even after the download fails and
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
index e9a0cb3b..15988c7 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
@@ -10,6 +10,7 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.components.offline_items_collection.ContentId;
+import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.OfflineItem.Progress;
 
 import java.util.ArrayList;
@@ -129,11 +130,13 @@
     }
 
     @Override
-    public void notifyDownloadFailed(final ContentId id, final String fileName, final Bitmap icon) {
+    public void notifyDownloadFailed(final ContentId id, final String fileName, final Bitmap icon,
+            @FailState int failState) {
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                MockDownloadNotificationService.super.notifyDownloadFailed(id, fileName, icon);
+                MockDownloadNotificationService.super.notifyDownloadFailed(
+                        id, fileName, icon, failState);
             }
         });
     }
@@ -148,4 +151,3 @@
         });
     }
 }
-
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandlerTest.java
index 8f11aab..cafa46c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarVoiceRecognitionHandlerTest.java
@@ -12,6 +12,7 @@
 import android.os.Bundle;
 import android.support.test.filters.SmallTest;
 import android.view.View;
+import android.view.ViewGroup;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -42,6 +43,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
 
 /**
  * Tests for {@link LocationBarVoiceRecognitionHandler}.
@@ -254,6 +256,19 @@
      */
     private class TestDelegate implements LocationBarVoiceRecognitionHandler.Delegate {
         private boolean mUpdatedMicButtonState;
+        private AutocompleteCoordinator mCoordinator;
+
+        TestDelegate() {
+            ViewGroup parent =
+                    (ViewGroup) mActivityTestRule.getActivity().findViewById(android.R.id.content);
+            Assert.assertNotNull(parent);
+            mCoordinator = new AutocompleteCoordinator(parent, null, null, null) {
+                @Override
+                public VoiceResult onVoiceResults(Bundle data) {
+                    return mAutocomplete.onVoiceResults(data);
+                }
+            };
+        }
 
         @Override
         public void loadUrlFromVoice(String url) {}
@@ -272,8 +287,8 @@
         }
 
         @Override
-        public AutocompleteController getAutocompleteController() {
-            return mAutocomplete;
+        public AutocompleteCoordinator getAutocompleteCoordinator() {
+            return mCoordinator;
         }
 
         @Override
@@ -401,11 +416,11 @@
     }
 
     @Before
-    public void setUp() throws InterruptedException {
+    public void setUp() throws InterruptedException, ExecutionException {
         mActivityTestRule.startMainActivityOnBlankPage();
 
         mDataProvider = new TestDataProvider();
-        mDelegate = new TestDelegate();
+        mDelegate = ThreadUtils.runOnUiThreadBlocking(() -> new TestDelegate());
         mHandler = new TestLocationBarVoiceRecognitionHandler(mDelegate);
         mPermissionDelegate = new TestAndroidPermissionDelegate();
         mAutocomplete = new LocalTestAutocompleteController(null /* view */,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
index 3d1452a..5803842 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -191,7 +191,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                locationBar.setAutocompleteController(controller);
+                locationBar.getAutocompleteCoordinator().setAutocompleteController(controller);
             }
         });
         Assert.assertEquals("Should not have any zero suggest requests yet", 0,
@@ -232,7 +232,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                locationBar.setAutocompleteController(controller);
+                locationBar.getAutocompleteCoordinator().setAutocompleteController(controller);
                 urlBar.setText("g");
             }
         });
@@ -277,7 +277,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                locationBar.setAutocompleteController(controller);
+                locationBar.getAutocompleteCoordinator().setAutocompleteController(controller);
                 urlBar.setText("g");
                 urlBar.setSelection(1);
             }
@@ -307,7 +307,7 @@
         ThreadUtils.runOnUiThreadBlocking(() -> {
             TestAutocompleteController controller = new TestAutocompleteController(locationBar,
                     sEmptySuggestionListener, new HashMap<String, List<SuggestionsResult>>());
-            locationBar.setAutocompleteController(controller);
+            locationBar.getAutocompleteCoordinator().setAutocompleteController(controller);
             locationBar.onWindowFocusChanged(false);
             locationBar.onWindowFocusChanged(true);
             Assert.assertEquals("Zero suggest not triggered when URL focused but unchanged", 1,
@@ -319,7 +319,7 @@
 
             TestAutocompleteController controller = new TestAutocompleteController(locationBar,
                     sEmptySuggestionListener, new HashMap<String, List<SuggestionsResult>>());
-            locationBar.setAutocompleteController(controller);
+            locationBar.getAutocompleteCoordinator().setAutocompleteController(controller);
             locationBar.onWindowFocusChanged(false);
             locationBar.onWindowFocusChanged(true);
             Assert.assertEquals("Zero suggest not triggered when URL focused but empty", 1,
@@ -331,7 +331,7 @@
         ThreadUtils.runOnUiThreadBlocking(() -> {
             urlBar.setText("cows");
 
-            locationBar.setAutocompleteController(controller);
+            locationBar.getAutocompleteCoordinator().setAutocompleteController(controller);
             locationBar.onWindowFocusChanged(false);
             locationBar.onWindowFocusChanged(true);
             Assert.assertEquals("Zero suggest incorrectly triggered when URL has changed", 0,
@@ -563,7 +563,8 @@
             public void onSuggestionsReceived(
                     List<OmniboxSuggestion> suggestions,
                     String inlineAutocompleteText) {
-                locationBar.onSuggestionsReceived(suggestions, inlineAutocompleteText);
+                locationBar.getAutocompleteCoordinator().onSuggestionsReceived(
+                        suggestions, inlineAutocompleteText);
                 synchronized (suggestionsProcessedSignal) {
                     int remaining = suggestionsLeft.decrementAndGet();
                     if (remaining == 0) {
@@ -580,7 +581,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                locationBar.setAutocompleteController(controller);
+                locationBar.getAutocompleteCoordinator().setAutocompleteController(controller);
             }
         });
 
@@ -883,12 +884,12 @@
                                 .addGeneratedSuggestion(OmniboxSuggestionType.SEARCH_HISTORY,
                                         "fac", null)));
         final TestAutocompleteController controller = new TestAutocompleteController(
-                locationBar, locationBar, suggestionsMap);
+                locationBar, locationBar.getAutocompleteCoordinator(), suggestionsMap);
 
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                locationBar.setAutocompleteController(controller);
+                locationBar.getAutocompleteCoordinator().setAutocompleteController(controller);
             }
         });
 
@@ -923,7 +924,8 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                OmniboxSuggestionsList suggestionsList = locationBar.getSuggestionList();
+                OmniboxSuggestionsList suggestionsList =
+                        locationBar.getAutocompleteCoordinator().getSuggestionList();
                 Assert.assertEquals(expectedSuggestionCount, suggestionsList.getChildCount());
                 for (int i = 0; i < suggestionsList.getChildCount(); i++) {
                     SuggestionView suggestionView = (SuggestionView) suggestionsList.getChildAt(i);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
index 16b6f19..d88a9304 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
@@ -129,8 +129,8 @@
                 LocationBarLayout locationBar =
                         (LocationBarLayout) mActivityTestRule.getActivity().findViewById(
                                 R.id.location_bar);
-                locationBar.cancelPendingAutocompleteStart();
-                locationBar.setAutocompleteController(controller);
+                locationBar.getAutocompleteCoordinator().cancelPendingAutocompleteStart();
+                locationBar.getAutocompleteCoordinator().setAutocompleteController(controller);
             }
         });
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java
index c5b1855..68d9d666 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiTest.java
@@ -30,7 +30,6 @@
 import org.chromium.chrome.browser.download.DownloadInfo;
 import org.chromium.chrome.browser.download.DownloadNotifier;
 import org.chromium.components.offline_items_collection.ContentId;
-import org.chromium.components.offline_items_collection.FailState;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
 import org.chromium.components.offline_items_collection.OfflineItemState;
@@ -165,8 +164,7 @@
                 .notifyDownloadInterrupted(argThat(new DownloadInfoIdMatcher(items.get(4).id)),
                         ArgumentMatchers.anyBoolean(), eq(PendingState.NOT_PENDING));
         verify(mNotifier, times(1))
-                .notifyDownloadFailed(argThat(new DownloadInfoIdMatcher(items.get(5).id)),
-                        eq(FailState.NO_FAILURE));
+                .notifyDownloadFailed(argThat(new DownloadInfoIdMatcher(items.get(5).id)));
         verify(mNotifier, times(1))
                 .notifyDownloadPaused(argThat(new DownloadInfoIdMatcher(items.get(6).id)));
 
diff --git a/chrome/app/file_manager_strings.grdp b/chrome/app/file_manager_strings.grdp
index fe623b2..649da9d 100644
--- a/chrome/app/file_manager_strings.grdp
+++ b/chrome/app/file_manager_strings.grdp
@@ -1036,12 +1036,21 @@
   <message name="IDS_FILE_BROWSER_NO_TASK_FOR_CRX" desc="Message shown when a user tries to open a *.crx file, which we don't handle in the Files app.">
     We're constantly looking for ways to make your browsing safer. Previously, any website could prompt you to add an extension into your browser. In the latest versions of Google Chrome, you must explicitly tell Chrome that you want to install these extensions by adding them through the Extensions page. <ph name="BEGIN_LINK">&lt;a target='_blank' href='https://support.google.com/chrome_webstore/answer/2664769?p=crx_warning&amp;rd=1'&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;</ph>
   </message>
-  <message name="IDS_FILE_BROWSER_UNABLE_TO_OPEN_CROSTINI_TITLE" desc="Message title shown when a user tries to use a crostini app to open a file outside the crostini container (e.g. in Downloads).  This message will be removed once we support this action.">
+  <message name="IDS_FILE_BROWSER_UNABLE_TO_OPEN_CROSTINI_TITLE" desc="Message title shown when a user tries to use a crostini app to open a file which cannot be shared with the crostini container (e.g. in Play or USB).  This message will be removed once we support this action.">
     Unable to open with $1
   </message>
-  <message name="IDS_FILE_BROWSER_UNABLE_TO_OPEN_CROSTINI" desc="Message shown when a user tries to use a crostini app to open a file outside the crostini container (e.g. in Downloads).  This message will be removed once we support this action.">
+  <message name="IDS_FILE_BROWSER_UNABLE_TO_OPEN_CROSTINI" desc="Message shown when a user tries to use a crostini app to open a file which cannot be shared with the crostini container (e.g. in Play or USB).  This message will be removed once we support this action.">
     To open files with $1, first copy to Linux files folder.
   </message>
+  <message name="IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_TITLE" desc="Message title shown when a user tries to use a crostini app to open a file outside the crostini container which can be shared with the container (e.g. in Downloads).">
+    Share files with Linux
+  </message>
+  <message name="IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_SINGLE" desc="Message shown when a user tries to use a crostini app to open a single file outside the crostini container which can be shared with the container (e.g. in Downloads).">
+    Let Linux apps open $1.
+  </message>
+  <message name="IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE" desc="Message shown when a user tries to use a crostini app to multiple files outside the crostini container which can be shared with the container (e.g. in Downloads).">
+    Let Linux apps open $1 files.
+  </message>
 
   <message name="IDS_FILE_BROWSER_FOLDER" desc="Folder entry type">
     Folder
diff --git a/chrome/app/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE.png.sha1 b/chrome/app/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE.png.sha1
new file mode 100644
index 0000000..1d7a7808
--- /dev/null
+++ b/chrome/app/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE.png.sha1
@@ -0,0 +1 @@
+848e13f48a12b5f1acf8e08366f66914133aca82
\ No newline at end of file
diff --git a/chrome/app/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_SINGLE.png.sha1 b/chrome/app/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_SINGLE.png.sha1
new file mode 100644
index 0000000..6dba2c5
--- /dev/null
+++ b/chrome/app/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_SINGLE.png.sha1
@@ -0,0 +1 @@
+1103d69da142202431923da3129ea3c1f33b0908
\ No newline at end of file
diff --git a/chrome/app/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_TITLE.png.sha1 b/chrome/app/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_TITLE.png.sha1
new file mode 100644
index 0000000..6dba2c5
--- /dev/null
+++ b/chrome/app/file_manager_strings_grdp/IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_TITLE.png.sha1
@@ -0,0 +1 @@
+1103d69da142202431923da3129ea3c1f33b0908
\ No newline at end of file
diff --git a/chrome/app_shim/chrome_main_app_mode_mac.mm b/chrome/app_shim/chrome_main_app_mode_mac.mm
index ae415b25..eebc32e 100644
--- a/chrome/app_shim/chrome_main_app_mode_mac.mm
+++ b/chrome/app_shim/chrome_main_app_mode_mac.mm
@@ -133,7 +133,7 @@
   // chrome::mojom::AppShim implementation.
   void LaunchAppDone(apps::AppShimLaunchResult result) override;
   void CreateViewsBridgeFactory(
-      views_bridge_mac::mojom::BridgeFactoryRequest request) override;
+      views_bridge_mac::mojom::BridgeFactoryAssociatedRequest request) override;
   void CreateContentNSViewBridgeFactory(
       content::mojom::NSViewBridgeFactoryAssociatedRequest request) override;
   void Hide() override;
@@ -224,7 +224,8 @@
       chrome::mojom::AppShimHostPtrInfo(std::move(message_pipe), 0));
 
   chrome::mojom::AppShimPtr app_shim_ptr;
-  shim_binding_.Bind(mojo::MakeRequest(&app_shim_ptr));
+  shim_binding_.Bind(mojo::MakeRequest(&app_shim_ptr),
+                     ui::WindowResizeHelperMac::Get()->task_runner());
   shim_binding_.set_connection_error_with_reason_handler(
       base::BindOnce(&AppShimController::ChannelError, base::Unretained(this)));
 
@@ -314,7 +315,7 @@
 }
 
 void AppShimController::CreateViewsBridgeFactory(
-    views_bridge_mac::mojom::BridgeFactoryRequest request) {
+    views_bridge_mac::mojom::BridgeFactoryAssociatedRequest request) {
   views_bridge_mac::BridgeFactoryImpl::Get()->BindRequest(std::move(request));
 }
 
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 5b336c6..b9295e96 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -222,6 +222,8 @@
     "browsing_data/counters/downloads_counter.h",
     "browsing_data/counters/media_licenses_counter.cc",
     "browsing_data/counters/media_licenses_counter.h",
+    "browsing_data/counters/signin_data_counter.cc",
+    "browsing_data/counters/signin_data_counter.h",
     "browsing_data/counters/site_data_counter.cc",
     "browsing_data/counters/site_data_counter.h",
     "browsing_data/counters/site_data_counting_helper.cc",
@@ -2118,6 +2120,8 @@
       "android/download/download_media_parser.h",
       "android/download/download_media_parser_bridge.cc",
       "android/download/download_media_parser_bridge.h",
+      "android/download/download_utils.cc",
+      "android/download/download_utils.h",
       "android/download/duplicate_download_infobar_delegate.cc",
       "android/download/duplicate_download_infobar_delegate.h",
       "android/download/intercept_download_resource_throttle.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 20db1f4..ded4115 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1451,6 +1451,9 @@
      flag_descriptions::kMediaScreenCaptureName,
      flag_descriptions::kMediaScreenCaptureDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(chrome::android::kUserMediaScreenCapturing)},
+    {"enable-surfacecontrol", flag_descriptions::kAndroidSurfaceControl,
+     flag_descriptions::kAndroidSurfaceControlDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(features::kAndroidSurfaceControl)},
 #endif  // OS_ANDROID
 // Native client is compiled out if ENABLE_NACL is not set.
 #if BUILDFLAG(ENABLE_NACL)
@@ -4085,10 +4088,6 @@
     {"ntp-icons", flag_descriptions::kNtpIconsName,
      flag_descriptions::kNtpIconsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kNtpIcons)},
-
-    {"ntp-ui-md", flag_descriptions::kNtpUIMdName,
-     flag_descriptions::kNtpUIMdDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(features::kNtpUIMd)},
 #endif  // OS_WIN || OS_MACOSX || OS_LINUX
 
 #if defined(OS_ANDROID)
diff --git a/chrome/browser/about_flags_unittest.cc b/chrome/browser/about_flags_unittest.cc
index 4bfbc8b..0e9da08e 100644
--- a/chrome/browser/about_flags_unittest.cc
+++ b/chrome/browser/about_flags_unittest.cc
@@ -148,8 +148,7 @@
            "kBadSwitchFormatHistogramId="
         << testing::kBadSwitchFormatHistogramId
         << ". Please modify switch name.";
-    SwitchToIdMap::iterator enum_entry =
-        histograms_xml_switches_ids.lower_bound(flag);
+    auto enum_entry = histograms_xml_switches_ids.lower_bound(flag);
 
     // Ignore case here when switch ID is incorrect - it has already been
     // reported in the previous loop.
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.cc b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
index a6dd975..6ea3f5be 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.cc
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.cc
@@ -124,16 +124,42 @@
   ui_delegate_->OnScriptSelected(script_path);
 }
 
+void UiControllerAndroid::OnAddressSelected(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller,
+    const base::android::JavaParamRef<jstring>& jaddress_guid) {
+  DCHECK(address_or_card_callback_);
+  std::string guid;
+  base::android::ConvertJavaStringToUTF8(env, jaddress_guid, &guid);
+  std::move(address_or_card_callback_).Run(guid);
+}
+
+void UiControllerAndroid::OnCardSelected(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller,
+    const base::android::JavaParamRef<jstring>& jcard_guid) {
+  DCHECK(address_or_card_callback_);
+  std::string guid;
+  base::android::ConvertJavaStringToUTF8(env, jcard_guid, &guid);
+  std::move(address_or_card_callback_).Run(guid);
+}
+
 void UiControllerAndroid::ChooseAddress(
     base::OnceCallback<void(const std::string&)> callback) {
-  // TODO(crbug.com/806868): Implement ChooseAddress.
-  std::move(callback).Run("");
+  DCHECK(!address_or_card_callback_);
+  address_or_card_callback_ = std::move(callback);
+  JNIEnv* env = AttachCurrentThread();
+  Java_AutofillAssistantUiController_onChooseAddress(
+      env, java_autofill_assistant_ui_controller_);
 }
 
 void UiControllerAndroid::ChooseCard(
     base::OnceCallback<void(const std::string&)> callback) {
-  // TODO(crbug.com/806868): Implement ChooseCard.
-  std::move(callback).Run("");
+  DCHECK(!address_or_card_callback_);
+  address_or_card_callback_ = std::move(callback);
+  JNIEnv* env = AttachCurrentThread();
+  Java_AutofillAssistantUiController_onChooseCard(
+      env, java_autofill_assistant_ui_controller_);
 }
 
 std::string UiControllerAndroid::GetApiKey() {
diff --git a/chrome/browser/android/autofill_assistant/ui_controller_android.h b/chrome/browser/android/autofill_assistant/ui_controller_android.h
index 8ae9a1a..6121c62 100644
--- a/chrome/browser/android/autofill_assistant/ui_controller_android.h
+++ b/chrome/browser/android/autofill_assistant/ui_controller_android.h
@@ -49,6 +49,13 @@
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& jcaller,
       const base::android::JavaParamRef<jstring>& jscript_path);
+  void OnAddressSelected(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& jcaller,
+      const base::android::JavaParamRef<jstring>& jaddress_guid);
+  void OnCardSelected(JNIEnv* env,
+                      const base::android::JavaParamRef<jobject>& jcaller,
+                      const base::android::JavaParamRef<jstring>& jcard_guid);
 
  private:
   // Java-side AutofillAssistantUiController object.
@@ -57,6 +64,8 @@
 
   UiDelegate* ui_delegate_;
 
+  base::OnceCallback<void(const std::string&)> address_or_card_callback_;
+
   DISALLOW_COPY_AND_ASSIGN(UiControllerAndroid);
 };
 
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index 7a74fffa..7b509767 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/download/download_core_service.h"
 #include "chrome/browser/download/download_core_service_factory.h"
+#include "chrome/browser/download/offline_item_utils.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "components/download/public/common/download_item.h"
 #include "content/public/browser/browser_context.h"
@@ -32,6 +33,7 @@
 using base::android::JavaParamRef;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
+using base::android::ConvertUTF16ToJavaString;
 using base::android::ScopedJavaLocalRef;
 
 namespace {
@@ -137,7 +139,10 @@
       ConvertUTF8ToJavaString(env, item->GetReferrerUrl().spec()),
       time_remaining_known ? time_delta.InMilliseconds()
                            : kUnknownRemainingTime,
-      item->GetLastAccessTime().ToJavaTime(), item->IsDangerous());
+      item->GetLastAccessTime().ToJavaTime(), item->IsDangerous(),
+      static_cast<int>(
+          OfflineItemUtils::ConvertDownloadInterruptReasonToFailState(
+              item->GetLastReason())));
 }
 
 static jlong JNI_DownloadManagerService_Init(JNIEnv* env,
diff --git a/chrome/browser/android/download/download_utils.cc b/chrome/browser/android/download/download_utils.cc
new file mode 100644
index 0000000..62b8540
--- /dev/null
+++ b/chrome/browser/android/download/download_utils.cc
@@ -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.
+
+#include "chrome/browser/android/download/download_utils.h"
+
+#include "base/android/jni_string.h"
+#include "chrome/browser/download/offline_item_utils.h"
+#include "jni/DownloadUtils_jni.h"
+
+using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
+static ScopedJavaLocalRef<jstring> JNI_DownloadUtils_GetFailStateMessage(
+    JNIEnv* env,
+    const JavaParamRef<jclass>& clazz,
+    jint fail_state) {
+  base::string16 message = OfflineItemUtils::GetFailStateMessage(
+      static_cast<offline_items_collection::FailState>(fail_state));
+  return ConvertUTF16ToJavaString(env, message);
+}
+
+// static
+base::FilePath DownloadUtils::GetUriStringForPath(
+    const base::FilePath& file_path) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  auto uri_jstring = Java_DownloadUtils_getUriStringForPath(
+      env,
+      base::android::ConvertUTF8ToJavaString(env, file_path.AsUTF8Unsafe()));
+  return base::FilePath(
+      base::android::ConvertJavaStringToUTF8(env, uri_jstring));
+}
diff --git a/chrome/browser/android/download/download_utils.h b/chrome/browser/android/download/download_utils.h
new file mode 100644
index 0000000..b507ffa
--- /dev/null
+++ b/chrome/browser/android/download/download_utils.h
@@ -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.
+
+#ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_UTILS_H_
+#define CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_UTILS_H_
+
+#include "base/files/file_path.h"
+
+// Native side of DownloadUtils.java.
+class DownloadUtils {
+ public:
+  static base::FilePath GetUriStringForPath(const base::FilePath& file_path);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_UTILS_H_
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher.cc b/chrome/browser/android/explore_sites/explore_sites_fetcher.cc
index 1bc1d4bc..6cd0a811 100644
--- a/chrome/browser/android/explore_sites/explore_sites_fetcher.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_fetcher.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/android/explore_sites/explore_sites_fetcher.h"
 
+#include <string>
 #include <utility>
 
 #include "base/bind.h"
@@ -17,8 +18,10 @@
 #include "chrome/browser/android/explore_sites/catalog.pb.h"
 #include "chrome/browser/android/explore_sites/explore_sites_types.h"
 #include "chrome/browser/android/explore_sites/url_util.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/chrome_accept_language_settings.h"
 #include "chrome/common/channel_info.h"
+#include "components/variations/service/variations_service.h"
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/storage_partition.h"
@@ -39,6 +42,27 @@
 
 namespace {
 
+std::string GetCountry() {
+  std::string manually_set_variation_country =
+      base::GetFieldTrialParamValueByFeature(chrome::android::kExploreSites,
+                                             "country_override");
+  if (!manually_set_variation_country.empty())
+    return manually_set_variation_country;
+
+  variations::VariationsService* variations_service =
+      g_browser_process->variations_service();
+  if (variations_service) {
+    std::string country = variations_service->GetStoredPermanentCountry();
+    if (!country.empty())
+      return country;
+    country = variations_service->GetLatestCountry();
+    if (!country.empty())
+      return country;
+  }
+
+  return "DEFAULT";
+}
+
 // Content type needed in order to communicate with the server in binary
 // proto format.
 const char kRequestContentType[] = "application/x-protobuf";
@@ -68,33 +92,30 @@
 std::unique_ptr<ExploreSitesFetcher> ExploreSitesFetcher::CreateForGetCatalog(
     Callback callback,
     const std::string catalog_version,
-    const std::string country_code,
     const std::string accept_languages,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory) {
   GURL url = GetCatalogURL();
   return base::WrapUnique(
       new ExploreSitesFetcher(std::move(callback), url, catalog_version,
-                              country_code, accept_languages, loader_factory));
+                              accept_languages, loader_factory));
 }
 
 std::unique_ptr<ExploreSitesFetcher>
 ExploreSitesFetcher::CreateForGetCategories(
     Callback callback,
     const std::string catalog_version,
-    const std::string country_code,
     const std::string accept_languages,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory) {
   GURL url = GetCategoriesURL();
   return base::WrapUnique(
       new ExploreSitesFetcher(std::move(callback), url, catalog_version,
-                              country_code, accept_languages, loader_factory));
+                              accept_languages, loader_factory));
 }
 
 ExploreSitesFetcher::ExploreSitesFetcher(
     Callback callback,
     const GURL& url,
     const std::string catalog_version,
-    const std::string country_code,
     const std::string accept_languages,
     scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
     : callback_(std::move(callback)),
@@ -109,9 +130,10 @@
                          version.components()[3],  // Patch
                          channel_name.c_str());
   GURL final_url =
-      net::AppendOrReplaceQueryParameter(url, "country_code", country_code);
+      net::AppendOrReplaceQueryParameter(url, "country_code", GetCountry());
   final_url = net::AppendOrReplaceQueryParameter(final_url, "version_token",
                                                  catalog_version);
+  DVLOG(1) << "Final URL: " << final_url.spec();
 
   auto resource_request = std::make_unique<network::ResourceRequest>();
   resource_request->url = final_url;
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher.h b/chrome/browser/android/explore_sites/explore_sites_fetcher.h
index 5cfe57b9..0f319d20 100644
--- a/chrome/browser/android/explore_sites/explore_sites_fetcher.h
+++ b/chrome/browser/android/explore_sites/explore_sites_fetcher.h
@@ -33,7 +33,6 @@
   static std::unique_ptr<ExploreSitesFetcher> CreateForGetCatalog(
       Callback callback,
       const std::string catalog_version,
-      const std::string country_code,
       const std::string accept_languages,
       scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
 
@@ -41,7 +40,6 @@
   static std::unique_ptr<ExploreSitesFetcher> CreateForGetCategories(
       Callback callback,
       const std::string catalog_version,
-      const std::string country_code,
       const std::string accept_languages,
       scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
 
@@ -52,7 +50,6 @@
       Callback callback,
       const GURL& url,
       const std::string catalog_version,
-      const std::string country_code,
       const std::string accept_languages,
       scoped_refptr<network ::SharedURLLoaderFactory> loader_factory);
 
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc b/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
index ac05eb46..01618cc 100644
--- a/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
@@ -4,11 +4,19 @@
 
 #include "chrome/browser/android/explore_sites/explore_sites_fetcher.h"
 
+#include <map>
+
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/test/bind_test_util.h"
 #include "base/test/mock_callback.h"
+#include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/test/test_mock_time_task_runner.h"
+#include "chrome/browser/android/chrome_feature_list.h"
 #include "chrome/browser/android/explore_sites/catalog.pb.h"
+#include "chrome/browser/android/explore_sites/explore_sites_feature.h"
 #include "chrome/browser/android/explore_sites/explore_sites_types.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
@@ -43,6 +51,25 @@
   ExploreSitesRequestStatus RunFetcherWithData(const std::string& response_data,
                                                std::string* data_received);
 
+  void SetUpExperimentOption(std::string country_code) {
+    const std::string kTrialName = "trial_name";
+    const std::string kGroupName = "group_name";
+
+    scoped_refptr<base::FieldTrial> trial =
+        base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+
+    std::map<std::string, std::string> params = {
+        {"country_override", country_code}};
+    base::AssociateFieldTrialParams(kTrialName, kGroupName, params);
+
+    std::unique_ptr<base::FeatureList> feature_list =
+        std::make_unique<base::FeatureList>();
+    feature_list->RegisterFieldTrialOverride(
+        chrome::android::kExploreSites.name,
+        base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial.get());
+    scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
+  }
+
   network::ResourceRequest last_resource_request;
 
  private:
@@ -64,6 +91,8 @@
   std::unique_ptr<std::string> last_data_;
   base::MessageLoopForIO message_loop_;
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+  std::unique_ptr<base::FieldTrialList> field_trial_list_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 ExploreSitesFetcher::Callback ExploreSitesFetcherTest::StoreResult() {
@@ -88,6 +117,8 @@
         EXPECT_TRUE(request.url.is_valid() && !request.url.is_empty());
         last_resource_request = request;
       }));
+  field_trial_list_ = std::make_unique<base::FieldTrialList>(
+      std::make_unique<base::MockEntropyProvider>());
 }
 
 ExploreSitesRequestStatus ExploreSitesFetcherTest::RunFetcherWithNetError(
@@ -160,7 +191,7 @@
     base::OnceCallback<void(void)> respond_callback,
     std::string* data_received) {
   std::unique_ptr<ExploreSitesFetcher> fetcher =
-      ExploreSitesFetcher::CreateForGetCatalog(StoreResult(), "123", "KE",
+      ExploreSitesFetcher::CreateForGetCatalog(StoreResult(), "123",
                                                kAcceptLanguages,
                                                test_shared_url_loader_factory_);
 
@@ -226,7 +257,20 @@
 
   EXPECT_EQ(last_resource_request.url.spec(),
             "https://exploresites-pa.googleapis.com/v1/"
-            "getcatalog?country_code=KE&version_token=123");
+            "getcatalog?country_code=DEFAULT&version_token=123");
+}
+
+TEST_F(ExploreSitesFetcherTest, DefaultCountry) {
+  SetUpExperimentOption("KZ");
+  std::string data;
+  EXPECT_EQ(ExploreSitesRequestStatus::kSuccess,
+            RunFetcherWithData("Any data.", &data));
+  EXPECT_FALSE(data.empty());
+  EXPECT_EQ(data, "Any data.");
+
+  EXPECT_EQ(last_resource_request.url.spec(),
+            "https://exploresites-pa.googleapis.com/v1/"
+            "getcatalog?country_code=KZ&version_token=123");
 }
 
 TEST_F(ExploreSitesFetcherTest, TestHeaders) {
diff --git a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
index a75d0aef..8f89885b 100644
--- a/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_service_impl.cc
@@ -79,14 +79,12 @@
 
   // TODO(petewil): Eventually get the catalog version from DB.
   std::string catalog_version = "";
-  // TODO(petewil): Eventually get the country code from somewhere.
-  std::string country_code = "KE";
 
   // Create a fetcher and start fetching the protobuf (async).
   explore_sites_fetcher_ = ExploreSitesFetcher::CreateForGetCatalog(
       base::BindOnce(&ExploreSitesServiceImpl::OnCatalogFetched,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
-      catalog_version, country_code, accept_languages, url_loader_factory_);
+      catalog_version, accept_languages, url_loader_factory_);
 }
 
 void ExploreSitesServiceImpl::OnCatalogFetched(
diff --git a/chrome/browser/android/logo_bridge.cc b/chrome/browser/android/logo_bridge.cc
index 660b2455..f24cee0 100644
--- a/chrome/browser/android/logo_bridge.cc
+++ b/chrome/browser/android/logo_bridge.cc
@@ -154,7 +154,7 @@
     JNIEnv* env = base::android::AttachCurrentThread();
 
     ScopedJavaLocalRef<jbyteArray> j_bytes = ToJavaByteArray(
-        env, reinterpret_cast<const uint8_t*>(response_body.get()),
+        env, reinterpret_cast<const uint8_t*>(response_body->data()),
         response_body->size());
     ScopedJavaLocalRef<jobject> j_gif_image =
         Java_LogoBridge_createGifImage(env, j_bytes);
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac.cc b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
index 5a148b2..f8ef148 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac.cc
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
@@ -17,6 +17,13 @@
 #include "ui/views/cocoa/bridge_factory_host.h"
 #include "ui/views_bridge_mac/mojo/bridge_factory.mojom.h"
 
+namespace {
+
+// Start counting host ids at 1000 to help in debugging.
+uint64_t g_next_host_id = 1000;
+
+}  // namespace
+
 AppShimHost::AppShimHost()
     : host_binding_(this), initial_launch_finished_(false) {}
 
@@ -69,11 +76,14 @@
 
   app_shim_ = std::move(app_shim_ptr);
   if (features::HostWindowsInAppShimProcess()) {
+    uint64_t host_id = g_next_host_id++;
+
     // Create the interface that will be used by views::NativeWidgetMac to
     // create NSWindows hosted in the app shim process.
-    views_bridge_mac::mojom::BridgeFactoryRequest views_bridge_factory_request;
+    views_bridge_mac::mojom::BridgeFactoryAssociatedRequest
+        views_bridge_factory_request;
     views_bridge_factory_host_ = std::make_unique<views::BridgeFactoryHost>(
-        &views_bridge_factory_request);
+        host_id, &views_bridge_factory_request);
     app_shim_->CreateViewsBridgeFactory(
         std::move(views_bridge_factory_request));
 
@@ -83,8 +93,7 @@
         content_bridge_factory_request;
     content_bridge_factory_ =
         std::make_unique<content::NSViewBridgeFactoryHost>(
-            &content_bridge_factory_request,
-            views_bridge_factory_host_->GetHostId());
+            &content_bridge_factory_request, host_id);
     app_shim_->CreateContentNSViewBridgeFactory(
         std::move(content_bridge_factory_request));
   }
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
index 5dec953..2058694 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac_unittest.cc
@@ -47,7 +47,8 @@
     launch_done_result_ = result;
   }
   void CreateViewsBridgeFactory(
-      views_bridge_mac::mojom::BridgeFactoryRequest request) override {}
+      views_bridge_mac::mojom::BridgeFactoryAssociatedRequest request)
+      override {}
   void CreateContentNSViewBridgeFactory(
       content::mojom::NSViewBridgeFactoryAssociatedRequest request) override {}
   void Hide() override {}
diff --git a/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm b/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
index 958be60..6bed870 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
+++ b/chrome/browser/apps/app_shim/app_shim_host_manager_browsertest_mac.mm
@@ -50,7 +50,8 @@
   // chrome::mojom::AppShim implementation (not used in testing, but can be).
   void LaunchAppDone(apps::AppShimLaunchResult result) override {}
   void CreateViewsBridgeFactory(
-      views_bridge_mac::mojom::BridgeFactoryRequest request) override {}
+      views_bridge_mac::mojom::BridgeFactoryAssociatedRequest request)
+      override {}
   void CreateContentNSViewBridgeFactory(
       content::mojom::NSViewBridgeFactoryAssociatedRequest request) override {}
   void Hide() override {}
diff --git a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_apitest.cc b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_apitest.cc
index 0bbb5c4..915d672 100644
--- a/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_apitest.cc
+++ b/chrome/browser/apps/platform_apps/api/media_galleries/media_galleries_apitest.cc
@@ -157,8 +157,7 @@
 
     // Make a copy, as the iterator would be invalidated otherwise.
     const MediaGalleriesPrefInfoMap galleries = preferences->known_galleries();
-    for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin();
-         it != galleries.end(); ++it) {
+    for (auto it = galleries.begin(); it != galleries.end(); ++it) {
       preferences->ForgetGalleryById(it->first);
     }
   }
diff --git a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc
index 6a0bc7e5..d1751c0 100644
--- a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc
+++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc
@@ -71,7 +71,7 @@
   // Look for first device name matching an entry of |kDeviceNames|.
   std::string result;
   for (size_t i = 0; i < arraysize(kDeviceNames); i++) {
-    DiskEntries::iterator it = disk_uuids.find(base::FilePath(kDeviceNames[i]));
+    auto it = disk_uuids.find(base::FilePath(kDeviceNames[i]));
     if (it != disk_uuids.end()) {
       DVLOG(1) << "Returning uuid: \"" << it->second.value()
                << "\" for device \"" << it->first.value() << "\"";
@@ -85,8 +85,7 @@
   if (result.empty() && !error_logged) {
     error_logged = true;
     LOG(ERROR) << "Could not find appropriate disk uuid.";
-    for (DiskEntries::iterator it = disk_uuids.begin(); it != disk_uuids.end();
-         ++it) {
+    for (auto it = disk_uuids.begin(); it != disk_uuids.end(); ++it) {
       LOG(ERROR) << "  DeviceID=" << it->first.value()
                  << ", uuid=" << it->second.value();
     }
diff --git a/chrome/browser/apps/platform_apps/app_browsertest_util.cc b/chrome/browser/apps/platform_apps/app_browsertest_util.cc
index e350ce5..0e863ce 100644
--- a/chrome/browser/apps/platform_apps/app_browsertest_util.cc
+++ b/chrome/browser/apps/platform_apps/app_browsertest_util.cc
@@ -89,7 +89,7 @@
   const AppWindowRegistry::AppWindowList& app_windows =
       app_registry->app_windows();
 
-  AppWindowRegistry::const_iterator iter = app_windows.begin();
+  auto iter = app_windows.begin();
   if (iter != app_windows.end())
     return *iter;
 
@@ -185,7 +185,7 @@
   const AppWindowRegistry::AppWindowList& app_windows =
       app_registry->GetAppWindowsForApp(app_id);
 
-  AppWindowRegistry::const_iterator iter = app_windows.begin();
+  auto iter = app_windows.begin();
   if (iter != app_windows.end())
     return *iter;
 
diff --git a/chrome/browser/apps/platform_apps/app_load_service.cc b/chrome/browser/apps/platform_apps/app_load_service.cc
index 30c99c883..7bc1bad 100644
--- a/chrome/browser/apps/platform_apps/app_load_service.cc
+++ b/chrome/browser/apps/platform_apps/app_load_service.cc
@@ -103,8 +103,7 @@
   // It is possible for an extension to be unloaded before it stops loading.
   if (!extension)
     return;
-  std::map<std::string, PostReloadAction>::iterator it =
-      post_reload_actions_.find(extension->id());
+  auto it = post_reload_actions_.find(extension->id());
   if (it == post_reload_actions_.end())
     return;
 
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
index 73bac4e..4f3936d 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -208,8 +208,7 @@
 
   std::vector<base::string16> builtins;
 
-  for (std::vector<std::string>::iterator i(chrome_builtins.begin());
-       i != chrome_builtins.end(); ++i)
+  for (auto i(chrome_builtins.begin()); i != chrome_builtins.end(); ++i)
     builtins.push_back(base::ASCIIToUTF16(*i));
 
 #if !defined(OS_ANDROID)
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc
index ab9160b..5d50503 100644
--- a/chrome/browser/autocomplete/search_provider_unittest.cc
+++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -63,7 +63,7 @@
 // Returns the first match in |matches| with |allowed_to_be_default_match|
 // set to true.
 ACMatches::const_iterator FindDefaultMatch(const ACMatches& matches) {
-  ACMatches::const_iterator it = matches.begin();
+  auto it = matches.begin();
   while ((it != matches.end()) && !it->allowed_to_be_default_match)
     ++it;
   return it;
@@ -477,8 +477,8 @@
 
 bool SearchProviderTest::FindMatchWithContents(const base::string16& contents,
                                                AutocompleteMatch* match) {
-  for (ACMatches::const_iterator i = provider_->matches().begin();
-       i != provider_->matches().end(); ++i) {
+  for (auto i = provider_->matches().begin(); i != provider_->matches().end();
+       ++i) {
     if (i->contents == contents) {
       *match = *i;
       return true;
@@ -489,8 +489,8 @@
 
 bool SearchProviderTest::FindMatchWithDestination(const GURL& url,
                                                   AutocompleteMatch* match) {
-  for (ACMatches::const_iterator i = provider_->matches().begin();
-       i != provider_->matches().end(); ++i) {
+  for (auto i = provider_->matches().begin(); i != provider_->matches().end();
+       ++i) {
     if (i->destination_url == url) {
       *match = *i;
       return true;
@@ -1970,7 +1970,7 @@
     ASSERT_FALSE(matches.empty());
     // Find the first match that's allowed to be the default match and check
     // its inline_autocompletion.
-    ACMatches::const_iterator it = FindDefaultMatch(matches);
+    auto it = FindDefaultMatch(matches);
     ASSERT_NE(matches.end(), it);
     EXPECT_EQ(ASCIIToUTF16(cases[i].inline_autocompletion),
               it->inline_autocompletion);
diff --git a/chrome/browser/autofill/captured_sites_test_utils.cc b/chrome/browser/autofill/captured_sites_test_utils.cc
index aea19786..e33bfc87 100644
--- a/chrome/browser/autofill/captured_sites_test_utils.cc
+++ b/chrome/browser/autofill/captured_sites_test_utils.cc
@@ -466,8 +466,8 @@
 
   base::Value::ListStorage& action_list = action_list_container->GetList();
 
-  for (base::ListValue::iterator it_action = action_list.begin();
-       it_action != action_list.end(); ++it_action) {
+  for (auto it_action = action_list.begin(); it_action != action_list.end();
+       ++it_action) {
     base::DictionaryValue* action;
     if (!it_action->GetAsDictionary(&action)) {
       ADD_FAILURE()
@@ -727,7 +727,7 @@
 
   const base::Value::ListStorage& commands_list =
       commands_list_container->GetList();
-  for (base::ListValue::const_iterator it_command = commands_list.begin();
+  for (auto it_command = commands_list.begin();
        it_command != commands_list.end(); ++it_command) {
     if (base::Value::Type::STRING != it_command->type()) {
       ADD_FAILURE() << "command is not a string!";
@@ -1429,7 +1429,7 @@
 
   const base::Value::ListStorage& profile_entries_list =
       saved_autofill_profile_container.GetList();
-  for (base::ListValue::const_iterator it_entry = profile_entries_list.begin();
+  for (auto it_entry = profile_entries_list.begin();
        it_entry != profile_entries_list.end(); ++it_entry) {
     const base::DictionaryValue* entry;
     if (!it_entry->GetAsDictionary(&entry)) {
@@ -1468,8 +1468,7 @@
 
   const base::Value::ListStorage& saved_password_list =
       saved_password_list_container.GetList();
-  for (base::ListValue::const_iterator it_password =
-           saved_password_list.begin();
+  for (auto it_password = saved_password_list.begin();
        it_password != saved_password_list.end(); ++it_password) {
     const base::DictionaryValue* cred;
     if (!it_password->GetAsDictionary(&cred)) {
diff --git a/chrome/browser/background/background_application_list_model_unittest.cc b/chrome/browser/background/background_application_list_model_unittest.cc
index b3816d8..bce56a3 100644
--- a/chrome/browser/background/background_application_list_model_unittest.cc
+++ b/chrome/browser/background/background_application_list_model_unittest.cc
@@ -357,7 +357,7 @@
                      size_t* expected,
                      size_t* count) {  // Maybe remove an extension.
   ExtensionRegistry* registry = ExtensionRegistry::Get(service->profile());
-  ExtensionCollection::iterator cursor = extensions->begin();
+  auto cursor = extensions->begin();
   if (cursor == extensions->end()) {
     // Nothing to remove.  Just verify accounting.
     ASSERT_EQ(0U, *count);
@@ -393,7 +393,7 @@
                       size_t* expected,
                       size_t* count) {
   ExtensionRegistry* registry = ExtensionRegistry::Get(service->profile());
-  ExtensionCollection::iterator cursor = extensions->begin();
+  auto cursor = extensions->begin();
   if (cursor == extensions->end()) {
     // Nothing to toggle.  Just verify accounting.
     ASSERT_EQ(0U, *count);
diff --git a/chrome/browser/background/background_contents_service.cc b/chrome/browser/background/background_contents_service.cc
index fc4c374..eca65516 100644
--- a/chrome/browser/background/background_contents_service.cc
+++ b/chrome/browser/background/background_contents_service.cc
@@ -298,8 +298,7 @@
 BackgroundContentsService::GetBackgroundContents() const
 {
   std::vector<BackgroundContents*> contents;
-  for (BackgroundContentsMap::const_iterator it = contents_map_.begin();
-       it != contents_map_.end(); ++it)
+  for (auto it = contents_map_.begin(); it != contents_map_.end(); ++it)
     contents.push_back(it->second.contents);
   return contents;
 }
@@ -806,8 +805,7 @@
 
 const std::string& BackgroundContentsService::GetParentApplicationId(
     BackgroundContents* contents) const {
-  for (BackgroundContentsMap::const_iterator it = contents_map_.begin();
-       it != contents_map_.end(); ++it) {
+  for (auto it = contents_map_.begin(); it != contents_map_.end(); ++it) {
     if (contents == it->second.contents)
       return it->first;
   }
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index 5b1d737e..3bc3253e 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -566,8 +566,7 @@
   DCHECK(success);
   base::string16 profile_name = entry->GetName();
   // Remove the profile from our map of profiles.
-  BackgroundModeInfoMap::iterator it =
-      GetBackgroundModeIterator(profile_name);
+  auto it = GetBackgroundModeIterator(profile_name);
   // If a profile isn't running a background app, it may not be in the map.
   if (it != background_mode_data_.end()) {
     it->second->applications()->RemoveObserver(this);
@@ -605,7 +604,7 @@
 BackgroundModeManager::GetBackgroundModeDataForLastProfile() const {
   Profile* most_recent_profile = g_browser_process->profile_manager()->
       GetLastUsedProfileAllowedByPolicy();
-  BackgroundModeInfoMap::const_iterator profile_background_data =
+  auto profile_background_data =
       background_mode_data_.find(most_recent_profile);
 
   if (profile_background_data == background_mode_data_.end())
@@ -1019,12 +1018,9 @@
 BackgroundModeManager::BackgroundModeInfoMap::iterator
 BackgroundModeManager::GetBackgroundModeIterator(
     const base::string16& profile_name) {
-  BackgroundModeInfoMap::iterator profile_it =
-      background_mode_data_.end();
-  for (BackgroundModeInfoMap::iterator it =
-       background_mode_data_.begin();
-       it != background_mode_data_.end();
-       ++it) {
+  auto profile_it = background_mode_data_.end();
+  for (auto it = background_mode_data_.begin();
+       it != background_mode_data_.end(); ++it) {
     if (it->second->name() == profile_name) {
       profile_it = it;
     }
diff --git a/chrome/browser/bookmarks/bookmark_html_writer.cc b/chrome/browser/bookmarks/bookmark_html_writer.cc
index a1e02fe..01455bd 100644
--- a/chrome/browser/bookmarks/bookmark_html_writer.cc
+++ b/chrome/browser/bookmarks/bookmark_html_writer.cc
@@ -270,8 +270,7 @@
       }
 
       std::string favicon_string;
-      BookmarkFaviconFetcher::URLFaviconMap::iterator itr =
-          favicons_map_->find(url_string);
+      auto itr = favicons_map_->find(url_string);
       if (itr != favicons_map_->end()) {
         scoped_refptr<base::RefCountedMemory> data(itr->second.get());
         std::string favicon_base64_encoded;
diff --git a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
index eb99f31..8a5b8a54 100644
--- a/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
+++ b/chrome/browser/bookmarks/bookmark_html_writer_unittest.cc
@@ -264,7 +264,7 @@
   for (size_t i = 0; i < favicons.size(); i++) {
     if (url1_favicon == favicons[i].favicon_url) {
       EXPECT_EQ(1U, favicons[i].urls.size());
-      std::set<GURL>::const_iterator iter = favicons[i].urls.find(url1);
+      auto iter = favicons[i].urls.find(url1);
       ASSERT_TRUE(iter != favicons[i].urls.end());
       ASSERT_TRUE(*iter == url1);
       ASSERT_TRUE(favicons[i].png_data == icon_data);
diff --git a/chrome/browser/browsing_data/browsing_data_cache_storage_helper.cc b/chrome/browser/browsing_data/browsing_data_cache_storage_helper.cc
index 3aa47de9..16601ac 100644
--- a/chrome/browser/browsing_data/browsing_data_cache_storage_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_cache_storage_helper.cc
@@ -149,8 +149,7 @@
 
 void CannedBrowsingDataCacheStorageHelper::DeleteCacheStorage(
     const GURL& origin) {
-  for (std::set<PendingCacheStorageUsageInfo>::iterator it =
-           pending_cache_storage_info_.begin();
+  for (auto it = pending_cache_storage_info_.begin();
        it != pending_cache_storage_info_.end();) {
     if (it->origin == origin)
       pending_cache_storage_info_.erase(it++);
diff --git a/chrome/browser/browsing_data/browsing_data_cache_storage_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_cache_storage_helper_browsertest.cc
index e134de66..7a52419 100644
--- a/chrome/browser/browsing_data/browsing_data_cache_storage_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_cache_storage_helper_browsertest.cc
@@ -47,7 +47,7 @@
   std::list<content::CacheStorageUsageInfo> result = callback.result();
 
   ASSERT_EQ(2U, result.size());
-  std::list<content::CacheStorageUsageInfo>::iterator info = result.begin();
+  auto info = result.begin();
   EXPECT_EQ(origin1, info->origin);
   info++;
   EXPECT_EQ(origin2, info->origin);
diff --git a/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc
index 9ab440b2..134b368 100644
--- a/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_cookie_helper_unittest.cc
@@ -94,8 +94,8 @@
     // For each cookie, look for a matching expectation.
     for (const auto& cookie : cookie_list_) {
       CookieMatcher matcher(cookie);
-      std::vector<CookieExpectation>::iterator match = std::find_if(
-          cookie_expectations_.begin(), cookie_expectations_.end(), matcher);
+      auto match = std::find_if(cookie_expectations_.begin(),
+                                cookie_expectations_.end(), matcher);
       if (match != cookie_expectations_.end())
         match->matched_ = true;
     }
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper.cc b/chrome/browser/browsing_data/browsing_data_database_helper.cc
index 7304055..c9ef62c 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_database_helper.cc
@@ -172,10 +172,8 @@
     const std::string& name) {
   GURL origin =
       storage::DatabaseIdentifier::Parse(origin_identifier).ToOrigin();
-  for (std::set<PendingDatabaseInfo>::iterator it =
-           pending_database_info_.begin();
-       it != pending_database_info_.end();
-       ++it) {
+  for (auto it = pending_database_info_.begin();
+       it != pending_database_info_.end(); ++it) {
     if (it->origin == origin && it->name == name) {
       pending_database_info_.erase(it);
       break;
diff --git a/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc
index 9e5b305..1eac320 100644
--- a/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_database_helper_browsertest.cc
@@ -107,8 +107,7 @@
       callback.result();
 
   ASSERT_EQ(3u, result.size());
-  std::list<BrowsingDataDatabaseHelper::DatabaseInfo>::iterator info =
-      result.begin();
+  auto info = result.begin();
   EXPECT_EQ(origin_str1, info->identifier.ToString());
   EXPECT_STREQ(db1, info->database_name.c_str());
   info++;
diff --git a/chrome/browser/browsing_data/browsing_data_file_system_helper.cc b/chrome/browser/browsing_data/browsing_data_file_system_helper.cc
index dff2b53e8..05aaa2b 100644
--- a/chrome/browser/browsing_data/browsing_data_file_system_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_file_system_helper.cc
@@ -122,9 +122,10 @@
         continue;  // Non-websafe state is not considered browsing data.
       int64_t usage = quota_util->GetOriginUsageOnFileTaskRunner(
           filesystem_context_.get(), current, type);
-      OriginInfoMap::iterator inserted =
-          file_system_info_map.insert(
-              std::make_pair(current, FileSystemInfo(current))).first;
+      auto inserted =
+          file_system_info_map
+              .insert(std::make_pair(current, FileSystemInfo(current)))
+              .first;
       inserted->second.usage_map[type] = usage;
     }
   }
diff --git a/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc b/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc
index 01d802c..8cb58dd 100644
--- a/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc
+++ b/chrome/browser/browsing_data/browsing_data_file_system_helper_unittest.cc
@@ -282,8 +282,7 @@
   FetchCannedFileSystems();
 
   EXPECT_EQ(2U, file_system_info_list_->size());
-  std::list<BrowsingDataFileSystemHelper::FileSystemInfo>::iterator info =
-      file_system_info_list_->begin();
+  auto info = file_system_info_list_->begin();
   EXPECT_EQ(kOrigin1, info->origin);
   EXPECT_TRUE(base::ContainsKey(info->usage_map, kPersistent));
   EXPECT_FALSE(base::ContainsKey(info->usage_map, kTemporary));
diff --git a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc b/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc
index ffd081e..3be1f6b 100644
--- a/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_flash_lso_helper.cc
@@ -98,8 +98,7 @@
 void BrowsingDataFlashLSOHelperImpl::OnClearSiteDataCompleted(
     uint32_t request_id,
     bool success) {
-  std::map<uint32_t, DeleteFlashLSOTask>::iterator entry =
-      clear_site_data_ids_.find(request_id);
+  auto entry = clear_site_data_ids_.find(request_id);
   DCHECK(entry != clear_site_data_ids_.end());
   LOG_IF(ERROR, !success) << "Couldn't clear Flash LSO data for "
                           << entry->second.site;
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
index 3087079..40c27cf 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper.cc
@@ -134,9 +134,8 @@
 
 void CannedBrowsingDataIndexedDBHelper::DeleteIndexedDB(
     const GURL& origin) {
-  for (std::set<PendingIndexedDBInfo>::iterator it =
-           pending_indexed_db_info_.begin();
-       it != pending_indexed_db_info_.end(); ) {
+  for (auto it = pending_indexed_db_info_.begin();
+       it != pending_indexed_db_info_.end();) {
     if (it->origin == origin)
       pending_indexed_db_info_.erase(it++);
     else
diff --git a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc
index 3cd3498..4f456c5 100644
--- a/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_indexed_db_helper_browsertest.cc
@@ -48,8 +48,7 @@
       callback.result();
 
   ASSERT_EQ(2U, result.size());
-  std::list<content::IndexedDBInfo>::iterator info =
-      result.begin();
+  auto info = result.begin();
   EXPECT_EQ(origin1, info->origin);
   info++;
   EXPECT_EQ(origin2, info->origin);
diff --git a/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc b/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc
index a043fcb9..37f653ce 100644
--- a/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc
+++ b/chrome/browser/browsing_data/browsing_data_local_storage_helper_browsertest.cc
@@ -166,8 +166,7 @@
       callback.result();
 
   ASSERT_EQ(2u, result.size());
-  std::list<BrowsingDataLocalStorageHelper::LocalStorageInfo>::iterator info =
-      result.begin();
+  auto info = result.begin();
   EXPECT_EQ(origin1, info->origin_url);
   info++;
   EXPECT_EQ(origin2, info->origin_url);
diff --git a/chrome/browser/browsing_data/browsing_data_service_worker_helper.cc b/chrome/browser/browsing_data/browsing_data_service_worker_helper.cc
index b5fe7eb..eac37bc7 100644
--- a/chrome/browser/browsing_data/browsing_data_service_worker_helper.cc
+++ b/chrome/browser/browsing_data/browsing_data_service_worker_helper.cc
@@ -156,8 +156,7 @@
 
 void CannedBrowsingDataServiceWorkerHelper::DeleteServiceWorkers(
     const GURL& origin) {
-  for (std::set<PendingServiceWorkerUsageInfo>::iterator it =
-           pending_service_worker_info_.begin();
+  for (auto it = pending_service_worker_info_.begin();
        it != pending_service_worker_info_.end();) {
     if (it->origin == origin)
       pending_service_worker_info_.erase(it++);
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
index f5174a6..456025f3 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.cc
@@ -139,7 +139,7 @@
 
 #if defined(OS_MACOSX)
 #include "components/os_crypt/os_crypt_pref_names_mac.h"
-#include "device/fido/mac/browsing_data_deletion.h"
+#include "device/fido/mac/credential_store.h"
 #endif  // defined(OS_MACOSX)
 
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -792,11 +792,10 @@
                              CreatePendingTaskCompletionClosureForMojo());
 
 #if defined(OS_MACOSX)
-    auto authenticator_config = ChromeAuthenticatorRequestDelegate::
-        TouchIdAuthenticatorConfigForProfile(profile_);
-    device::fido::mac::DeleteWebAuthnCredentials(
-        authenticator_config.keychain_access_group,
-        authenticator_config.metadata_secret, delete_begin_, delete_end_);
+    device::fido::mac::TouchIdCredentialStore(
+        ChromeAuthenticatorRequestDelegate::
+            TouchIdAuthenticatorConfigForProfile(profile_))
+        .DeleteCredentials(delete_begin_, delete_end_);
 
     // When clearing passwords for all time, reset preferences that are used to
     // prevent overwriting the encryption key in the Keychain.
diff --git a/chrome/browser/browsing_data/cookies_tree_model.cc b/chrome/browser/browsing_data/cookies_tree_model.cc
index 56381c09..a5aad9c 100644
--- a/chrome/browser/browsing_data/cookies_tree_model.cc
+++ b/chrome/browser/browsing_data/cookies_tree_model.cc
@@ -1319,8 +1319,8 @@
       CookieTreeAppCachesNode* appcaches_node =
           host_node->GetOrCreateAppCachesNode();
 
-      for (std::list<AppCacheInfo>::iterator info = origin.second.begin();
-           info != origin.second.end(); ++info) {
+      for (auto info = origin.second.begin(); info != origin.second.end();
+           ++info) {
         appcaches_node->AddAppCacheNode(
             std::make_unique<CookieTreeAppCacheNode>(origin.first, info));
       }
@@ -1335,7 +1335,7 @@
   CookieTreeRootNode* root = static_cast<CookieTreeRootNode*>(GetRoot());
 
   notifier->StartBatchUpdate();
-  for (CookieList::iterator it = container->cookie_list_.begin();
+  for (auto it = container->cookie_list_.begin();
        it != container->cookie_list_.end(); ++it) {
     std::string domain = it->Domain();
     if (domain.length() > 1 && domain[0] == '.')
@@ -1365,10 +1365,8 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (DatabaseInfoList::iterator database_info =
-           container->database_info_list_.begin();
-       database_info != container->database_info_list_.end();
-       ++database_info) {
+  for (auto database_info = container->database_info_list_.begin();
+       database_info != container->database_info_list_.end(); ++database_info) {
     GURL origin(database_info->identifier.ToOrigin());
 
     if (filter.empty() || (CookieTreeHostNode::TitleForUrl(origin)
@@ -1392,8 +1390,7 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (LocalStorageInfoList::iterator local_storage_info =
-           container->local_storage_info_list_.begin();
+  for (auto local_storage_info = container->local_storage_info_list_.begin();
        local_storage_info != container->local_storage_info_list_.end();
        ++local_storage_info) {
     const GURL& origin(local_storage_info->origin_url);
@@ -1419,7 +1416,7 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (LocalStorageInfoList::iterator session_storage_info =
+  for (auto session_storage_info =
            container->session_storage_info_list_.begin();
        session_storage_info != container->session_storage_info_list_.end();
        ++session_storage_info) {
@@ -1446,8 +1443,7 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (IndexedDBInfoList::iterator indexed_db_info =
-           container->indexed_db_info_list_.begin();
+  for (auto indexed_db_info = container->indexed_db_info_list_.begin();
        indexed_db_info != container->indexed_db_info_list_.end();
        ++indexed_db_info) {
     const GURL& origin = indexed_db_info->origin;
@@ -1473,8 +1469,7 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (ChannelIDList::iterator channel_id_info =
-           container->channel_id_list_.begin();
+  for (auto channel_id_info = container->channel_id_list_.begin();
        channel_id_info != container->channel_id_list_.end();
        ++channel_id_info) {
     GURL origin(channel_id_info->server_identifier());
@@ -1506,8 +1501,7 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (ServiceWorkerUsageInfoList::iterator service_worker_info =
-           container->service_worker_info_list_.begin();
+  for (auto service_worker_info = container->service_worker_info_list_.begin();
        service_worker_info != container->service_worker_info_list_.end();
        ++service_worker_info) {
     const GURL& origin = service_worker_info->origin;
@@ -1533,8 +1527,7 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (SharedWorkerInfoList::iterator shared_worker_info =
-           container->shared_worker_info_list_.begin();
+  for (auto shared_worker_info = container->shared_worker_info_list_.begin();
        shared_worker_info != container->shared_worker_info_list_.end();
        ++shared_worker_info) {
     const GURL& worker = shared_worker_info->worker;
@@ -1560,8 +1553,7 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (CacheStorageUsageInfoList::iterator cache_storage_info =
-           container->cache_storage_info_list_.begin();
+  for (auto cache_storage_info = container->cache_storage_info_list_.begin();
        cache_storage_info != container->cache_storage_info_list_.end();
        ++cache_storage_info) {
     const GURL& origin = cache_storage_info->origin;
@@ -1587,8 +1579,7 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (FileSystemInfoList::iterator file_system_info =
-           container->file_system_info_list_.begin();
+  for (auto file_system_info = container->file_system_info_list_.begin();
        file_system_info != container->file_system_info_list_.end();
        ++file_system_info) {
     GURL origin(file_system_info->origin);
@@ -1614,9 +1605,8 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (QuotaInfoList::iterator quota_info = container->quota_info_list_.begin();
-       quota_info != container->quota_info_list_.end();
-       ++quota_info) {
+  for (auto quota_info = container->quota_info_list_.begin();
+       quota_info != container->quota_info_list_.end(); ++quota_info) {
     if (filter.empty() || (base::UTF8ToUTF16(quota_info->host).find(filter) !=
                            base::string16::npos)) {
       CookieTreeHostNode* host_node =
@@ -1637,8 +1627,7 @@
 
   std::string filter_utf8 = base::UTF16ToUTF8(filter);
   notifier->StartBatchUpdate();
-  for (std::vector<std::string>::iterator it =
-           container->flash_lso_domain_list_.begin();
+  for (auto it = container->flash_lso_domain_list_.begin();
        it != container->flash_lso_domain_list_.end(); ++it) {
     if (filter_utf8.empty() || it->find(filter_utf8) != std::string::npos) {
       // Create a fake origin for GetOrCreateHostNode().
@@ -1659,8 +1648,7 @@
     return;
 
   notifier->StartBatchUpdate();
-  for (MediaLicenseInfoList::iterator media_license_info =
-           container->media_license_info_list_.begin();
+  for (auto media_license_info = container->media_license_info_list_.begin();
        media_license_info != container->media_license_info_list_.end();
        ++media_license_info) {
     GURL origin(media_license_info->origin);
diff --git a/chrome/browser/browsing_data/counters/browsing_data_counter_factory.cc b/chrome/browser/browsing_data/counters/browsing_data_counter_factory.cc
index 1dc8a709..b44c1faa 100644
--- a/chrome/browser/browsing_data/counters/browsing_data_counter_factory.cc
+++ b/chrome/browser/browsing_data/counters/browsing_data_counter_factory.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/browsing_data/counters/cache_counter.h"
 #include "chrome/browser/browsing_data/counters/downloads_counter.h"
 #include "chrome/browser/browsing_data/counters/media_licenses_counter.h"
+#include "chrome/browser/browsing_data/counters/signin_data_counter.h"
 #include "chrome/browser/browsing_data/counters/site_data_counter.h"
 #include "chrome/browser/browsing_data/counters/site_settings_counter.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -21,6 +22,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/web_data_service_factory.h"
+#include "chrome/browser/webauthn/chrome_authenticator_request_delegate.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/browsing_data/core/counters/autofill_counter.h"
 #include "components/browsing_data/core/counters/browsing_data_counter.h"
@@ -39,6 +41,10 @@
 #include "content/public/browser/host_zoom_map.h"
 #endif
 
+#if defined(OS_MACOSX)
+#include "device/fido/mac/credential_store.h"
+#endif
+
 namespace {
 
 history::WebHistoryService* GetUpdatedWebHistoryService(Profile* profile) {
@@ -55,8 +61,7 @@
     return std::make_unique<browsing_data::HistoryCounter>(
         HistoryServiceFactory::GetForProfile(
             profile, ServiceAccessType::EXPLICIT_ACCESS),
-        base::Bind(&GetUpdatedWebHistoryService,
-                   base::Unretained(profile)),
+        base::Bind(&GetUpdatedWebHistoryService, base::Unretained(profile)),
         ProfileSyncServiceFactory::GetForProfile(profile));
   }
   if (pref_name == browsing_data::prefs::kDeleteBrowsingHistoryBasic) {
@@ -83,10 +88,19 @@
   }
 
   if (pref_name == browsing_data::prefs::kDeletePasswords) {
-    return std::make_unique<browsing_data::PasswordsCounter>(
+    std::unique_ptr<::device::fido::PlatformCredentialStore> credential_store =
+#if defined(OS_MACOSX)
+        std::make_unique<::device::fido::mac::TouchIdCredentialStore>(
+            ChromeAuthenticatorRequestDelegate::
+                TouchIdAuthenticatorConfigForProfile(profile));
+#else
+        nullptr;
+#endif
+    return std::make_unique<browsing_data::SigninDataCounter>(
         PasswordStoreFactory::GetForProfile(profile,
                                             ServiceAccessType::EXPLICIT_ACCESS),
-        ProfileSyncServiceFactory::GetForProfile(profile));
+        ProfileSyncServiceFactory::GetForProfile(profile),
+        std::move(credential_store));
   }
 
   if (pref_name == browsing_data::prefs::kDeleteFormData) {
diff --git a/chrome/browser/browsing_data/counters/browsing_data_counter_utils.cc b/chrome/browser/browsing_data/counters/browsing_data_counter_utils.cc
index 1f67278..1f208ec 100644
--- a/chrome/browser/browsing_data/counters/browsing_data_counter_utils.cc
+++ b/chrome/browser/browsing_data/counters/browsing_data_counter_utils.cc
@@ -8,6 +8,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/browsing_data/counters/cache_counter.h"
 #include "chrome/browser/browsing_data/counters/media_licenses_counter.h"
+#include "chrome/browser/browsing_data/counters/signin_data_counter.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -190,5 +191,43 @@
   }
 #endif
 
+  if (pref_name == browsing_data::prefs::kDeletePasswords) {
+    const browsing_data::SigninDataCounter::SigninDataResult*
+        passwords_and_signin_data_result = static_cast<
+            const browsing_data::SigninDataCounter::SigninDataResult*>(result);
+
+    browsing_data::BrowsingDataCounter::ResultInt password_count =
+        passwords_and_signin_data_result->Value();
+    browsing_data::BrowsingDataCounter::ResultInt signin_data_count =
+        passwords_and_signin_data_result->WebAuthnCredentialsValue();
+
+    std::vector<base::string16> counts;
+    if (password_count) {
+      counts.emplace_back(l10n_util::GetPluralStringFUTF16(
+          passwords_and_signin_data_result->is_sync_enabled()
+              ? IDS_DEL_PASSWORDS_COUNTER_SYNCED
+              : IDS_DEL_PASSWORDS_COUNTER,
+          password_count));
+    }
+    if (signin_data_count) {
+      counts.emplace_back(l10n_util::GetPluralStringFUTF16(
+          IDS_DEL_SIGNIN_DATA_COUNTER, signin_data_count));
+    }
+    switch (counts.size()) {
+      case 0:
+        return l10n_util::GetStringUTF16(
+            IDS_DEL_PASSWORDS_AND_SIGNIN_DATA_COUNTER_NONE);
+      case 1:
+        return counts[0];
+      case 2:
+        return l10n_util::GetStringFUTF16(
+            IDS_DEL_PASSWORDS_AND_SIGNIN_DATA_COUNTER_COMBINATION, counts[0],
+            counts[1]);
+      default:
+        NOTREACHED();
+    }
+    NOTREACHED();
+  }
+
   return browsing_data::GetCounterTextFromResult(result);
 }
diff --git a/chrome/browser/browsing_data/counters/browsing_data_counter_utils_unittest.cc b/chrome/browser/browsing_data/counters/browsing_data_counter_utils_unittest.cc
index b33dd074..49948f2 100644
--- a/chrome/browser/browsing_data/counters/browsing_data_counter_utils_unittest.cc
+++ b/chrome/browser/browsing_data/counters/browsing_data_counter_utils_unittest.cc
@@ -11,8 +11,12 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browsing_data/counters/cache_counter.h"
+#include "chrome/browser/browsing_data/counters/signin_data_counter.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/password_manager/core/browser/test_password_store.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/buildflags/buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -109,19 +113,16 @@
 
   for (const TestCase& test_case : kTestCases) {
     // Split the list of installed apps by commas.
-    std::vector<std::string> apps = base::SplitString(
-        test_case.apps_list, ",",
-        base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+    std::vector<std::string> apps =
+        base::SplitString(test_case.apps_list, ",", base::TRIM_WHITESPACE,
+                          base::SPLIT_WANT_NONEMPTY);
 
     // The first two apps in the list are used as examples.
     std::vector<std::string> examples;
-    examples.assign(
-        apps.begin(), apps.begin() + (apps.size() > 2 ? 2 : apps.size()));
+    examples.assign(apps.begin(),
+                    apps.begin() + (apps.size() > 2 ? 2 : apps.size()));
 
-    HostedAppsCounter::HostedAppsResult result(
-        &counter,
-        apps.size(),
-        examples);
+    HostedAppsCounter::HostedAppsResult result(&counter, apps.size(), examples);
 
     base::string16 output =
         GetChromeCounterTextFromResult(&result, GetProfile());
@@ -173,3 +174,50 @@
       << output;
 }
 #endif
+
+// Tests the output for "Passwords and other sign-in data" on the advanced tab.
+TEST_F(BrowsingDataCounterUtilsTest, DeletePasswordsAndSigninData) {
+  // This test assumes that the strings are served exactly as defined,
+  // i.e. that the locale is set to the default "en".
+  ASSERT_EQ("en", TestingBrowserProcess::GetGlobal()->GetApplicationLocale());
+
+  auto password_store =
+      base::MakeRefCounted<password_manager::TestPasswordStore>();
+
+  // This counter does not really count anything; we just need a reference to
+  // pass to the SigninDataResult ctor.
+  browsing_data::SigninDataCounter counter(
+      password_store, ProfileSyncServiceFactory::GetForProfile(GetProfile()),
+      nullptr);
+
+  const struct TestCase {
+    int num_passwords;
+    int num_webauthn_credentials;
+    bool sync_enabled;
+    std::string expected_output;
+  } kTestCases[] = {
+      {0, 0, false, "None"},
+      {0, 0, true, "None"},
+      {1, 0, false, "1 password"},
+      {1, 0, true, "1 password (synced)"},
+      {2, 0, false, "2 passwords"},
+      {2, 0, true, "2 passwords (synced)"},
+      {0, 1, false, "sign-in data for 1 account"},
+      {0, 1, true, "sign-in data for 1 account"},
+      {0, 2, false, "sign-in data for 2 accounts"},
+      {0, 2, true, "sign-in data for 2 accounts"},
+      {1, 2, false, "1 password; sign-in data for 2 accounts"},
+      {2, 1, false, "2 passwords; sign-in data for 1 account"},
+      {2, 3, true, "2 passwords (synced); sign-in data for 3 accounts"},
+  };
+  for (const auto& test_case : kTestCases) {
+    browsing_data::SigninDataCounter::SigninDataResult result(
+        &counter, test_case.num_passwords, test_case.num_webauthn_credentials,
+        test_case.sync_enabled);
+    std::string output = base::UTF16ToASCII(
+        GetChromeCounterTextFromResult(&result, GetProfile()));
+    EXPECT_EQ(test_case.expected_output, output);
+  }
+
+  password_store->ShutdownOnUIThread();
+}
diff --git a/chrome/browser/browsing_data/counters/signin_data_counter.cc b/chrome/browser/browsing_data/counters/signin_data_counter.cc
new file mode 100644
index 0000000..6b3d7b41
--- /dev/null
+++ b/chrome/browser/browsing_data/counters/signin_data_counter.cc
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/browsing_data/counters/signin_data_counter.h"
+
+namespace browsing_data {
+
+SigninDataCounter::SigninDataCounter(
+    scoped_refptr<password_manager::PasswordStore> store,
+    syncer::SyncService* sync_service,
+    std::unique_ptr<::device::fido::PlatformCredentialStore>
+        opt_platform_credential_store)
+    : PasswordsCounter(store, sync_service),
+      credential_store_(std::move(opt_platform_credential_store)) {}
+
+SigninDataCounter::~SigninDataCounter() = default;
+
+int SigninDataCounter::CountWebAuthnCredentials() {
+  return credential_store_ ? credential_store_->CountCredentials(
+                                 GetPeriodStart(), GetPeriodEnd())
+                           : 0;
+}
+
+std::unique_ptr<BrowsingDataCounter::SyncResult>
+SigninDataCounter::MakeResult() {
+  return std::make_unique<SigninDataResult>(
+      this, num_passwords(), CountWebAuthnCredentials(), is_sync_active());
+}
+
+SigninDataCounter::SigninDataResult::SigninDataResult(
+    const SigninDataCounter* source,
+    ResultInt num_passwords,
+    ResultInt num_webauthn_credentials,
+    bool sync_enabled)
+    : BrowsingDataCounter::SyncResult(source, num_passwords, sync_enabled),
+      num_webauthn_credentials_(num_webauthn_credentials) {}
+
+SigninDataCounter::SigninDataResult::~SigninDataResult() {}
+
+}  // namespace browsing_data
diff --git a/chrome/browser/browsing_data/counters/signin_data_counter.h b/chrome/browser/browsing_data/counters/signin_data_counter.h
new file mode 100644
index 0000000..bb2fee5d
--- /dev/null
+++ b/chrome/browser/browsing_data/counters/signin_data_counter.h
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_BROWSING_DATA_COUNTERS_SIGNIN_DATA_COUNTER_H_
+#define CHROME_BROWSER_BROWSING_DATA_COUNTERS_SIGNIN_DATA_COUNTER_H_
+
+#include <memory>
+#include <vector>
+
+#include "components/browsing_data/core/counters/passwords_counter.h"
+#include "device/fido/platform_credential_store.h"
+
+namespace browsing_data {
+
+class SigninDataCounter : public PasswordsCounter {
+ public:
+  class SigninDataResult : public SyncResult {
+   public:
+    SigninDataResult(const SigninDataCounter* source,
+                     ResultInt num_passwords,
+                     ResultInt num_webauthn_credentials,
+                     bool sync_enabled);
+    ~SigninDataResult() override;
+
+    ResultInt WebAuthnCredentialsValue() const {
+      return num_webauthn_credentials_;
+    }
+
+   private:
+    ResultInt num_webauthn_credentials_;
+  };
+
+  explicit SigninDataCounter(
+      scoped_refptr<password_manager::PasswordStore> password_store,
+      syncer::SyncService* sync_service,
+      std::unique_ptr<::device::fido::PlatformCredentialStore>
+          opt_platform_credential_store);
+  ~SigninDataCounter() override;
+
+ private:
+  int CountWebAuthnCredentials();
+  std::unique_ptr<SyncResult> MakeResult() override;
+
+  std::unique_ptr<::device::fido::PlatformCredentialStore> credential_store_;
+};
+
+}  // namespace browsing_data
+
+#endif  // CHROME_BROWSER_BROWSING_DATA_COUNTERS_SIGNIN_DATA_COUNTER_H_
diff --git a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc b/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc
index 0d88320..5d9058ff8 100644
--- a/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc
+++ b/chrome/browser/browsing_data/mock_browsing_data_flash_lso_helper.cc
@@ -21,8 +21,7 @@
 void MockBrowsingDataFlashLSOHelper::DeleteFlashLSOsForSite(
     const std::string& site,
     base::OnceClosure callback) {
-  std::vector<std::string>::iterator entry =
-      std::find(domains_.begin(), domains_.end(), site);
+  auto entry = std::find(domains_.begin(), domains_.end(), site);
   ASSERT_TRUE(entry != domains_.end());
   domains_.erase(entry);
   if (!callback.is_null())
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index 2acdc1eb..f18b1c1e 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -245,8 +245,7 @@
 
 int MultiNavigationObserver::NumNavigationsForTab(
     WebContents* web_contents) const {
-  TabNavigationMap::const_iterator tab_navigations =
-      tab_navigation_map_.find(web_contents);
+  auto tab_navigations = tab_navigation_map_.find(web_contents);
   if (tab_navigations == tab_navigation_map_.end())
     return 0;
   return tab_navigations->second;
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index b038d1b..59a4e73 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1960,8 +1960,7 @@
           prefs->GetList(prefs::kEnableDeprecatedWebPlatformFeatures);
       if (switches) {
         // Enable any deprecated features that have been re-enabled by policy.
-        for (base::ListValue::const_iterator it = switches->begin();
-             it != switches->end(); ++it) {
+        for (auto it = switches->begin(); it != switches->end(); ++it) {
           std::string switch_to_enable;
           if (it->GetAsString(&switch_to_enable))
             command_line->AppendSwitch(switch_to_enable);
diff --git a/chrome/browser/chromeos/accessibility/DEPS b/chrome/browser/chromeos/accessibility/DEPS
index 190a10c..d40c29d 100644
--- a/chrome/browser/chromeos/accessibility/DEPS
+++ b/chrome/browser/chromeos/accessibility/DEPS
@@ -7,11 +7,6 @@
     # TODO(mash): Fix. https://crbug.com/647781
     "+ash/sticky_keys/sticky_keys_controller.h",
   ],
-  "ax_host_service\.cc": [
-    # TODO(mash): Fix. https://crbug.com/888145
-    "+ash/accessibility/accessibility_controller.h",
-    "+ash/shell.h",
-  ],
   "magnification_manager\.cc": [
     # TODO(mash): Fix. https://crbug.com/817157
     "+ash/magnifier/magnification_controller.h",
diff --git a/chrome/browser/chromeos/accessibility/ax_host_service.cc b/chrome/browser/chromeos/accessibility/ax_host_service.cc
index 18c0281e..b291295a 100644
--- a/chrome/browser/chromeos/accessibility/ax_host_service.cc
+++ b/chrome/browser/chromeos/accessibility/ax_host_service.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/chromeos/accessibility/ax_host_service.h"
 
-#include "ash/accessibility/accessibility_controller.h"
-#include "ash/shell.h"
 #include "base/bind.h"
 #include "chrome/browser/extensions/api/automation_internal/automation_event_router.h"
 #include "chrome/common/extensions/chrome_extension_messages.h"
@@ -23,13 +21,6 @@
   // AX tree ID is automatically assigned.
   DCHECK_NE(tree_id(), ui::AXTreeIDUnknown());
 
-  // ash::Shell may not exist in tests.
-  if (ash::Shell::HasInstance()) {
-    // TODO(jamescook): Eliminate this when tree ID assignment is handed in ash.
-    ash::Shell::Get()->accessibility_controller()->set_remote_ax_tree_id(
-        tree_id());
-  }
-
   DCHECK(!instance_);
   instance_ = this;
   registry_.AddInterface<ax::mojom::AXHost>(
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
index 569c37e..31a2887 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -376,10 +376,14 @@
   return container_username;
 }
 
-base::FilePath HomeDirectoryForProfile(Profile* profile) {
+base::FilePath ContainerHomeDirectoryForProfile(Profile* profile) {
   return base::FilePath("/home/" + ContainerUserNameForProfile(profile));
 }
 
+base::FilePath ContainerChromeOSBaseDirectory() {
+  return base::FilePath("/ChromeOS/");
+}
+
 std::string AppNameFromCrostiniAppId(const std::string& id) {
   return kCrostiniAppNamePrefix + id;
 }
diff --git a/chrome/browser/chromeos/crostini/crostini_util.h b/chrome/browser/chromeos/crostini/crostini_util.h
index 26c0b938..4c0bc89 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.h
+++ b/chrome/browser/chromeos/crostini/crostini_util.h
@@ -75,7 +75,11 @@
 std::string ContainerUserNameForProfile(Profile* profile);
 
 // Returns the home directory within the container for a given profile.
-base::FilePath HomeDirectoryForProfile(Profile* profile);
+base::FilePath ContainerHomeDirectoryForProfile(Profile* profile);
+
+// Returns the mount directory within the container where paths from the Chrome
+// OS host such as within Downloads are shared with the container.
+base::FilePath ContainerChromeOSBaseDirectory();
 
 // The Terminal opens Crosh but overrides the Browser's app_name so that we can
 // identify it as the Crostini Terminal. In the future, we will also use these
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index fb6585f..75a0736 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -758,6 +758,12 @@
   SET_STRING("MEDIA_TITLE_COLUMN_LABEL",
              IDS_FILE_BROWSER_MEDIA_TITLE_COLUMN_LABEL);
   SET_STRING("RECENT_ROOT_LABEL", IDS_FILE_BROWSER_RECENT_ROOT_LABEL);
+  SET_STRING("SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE",
+             IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE);
+  SET_STRING("SHARE_BEFORE_OPEN_CROSTINI_SINGLE",
+             IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_SINGLE);
+  SET_STRING("SHARE_BEFORE_OPEN_CROSTINI_TITLE",
+             IDS_FILE_BROWSER_SHARE_BEFORE_OPEN_CROSTINI_TITLE);
   SET_STRING("SUGGEST_DIALOG_INSTALLATION_FAILED",
              IDS_FILE_BROWSER_SUGGEST_DIALOG_INSTALLATION_FAILED);
   SET_STRING("SUGGEST_DIALOG_LINK_TO_WEBSTORE",
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index cb9622c4..4e6d07a 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -230,7 +230,8 @@
 #if defined(ADDRESS_SANITIZER)
 #define MAYBE_ZipFiles DISABLED_ZipFiles
 #else
-#define MAYBE_ZipFiles ZipFiles
+// ZipFiles tests are flaking consistently: http://crbug.com/891116
+#define MAYBE_ZipFiles DISABLED_ZipFiles
 #endif
 WRAPPED_INSTANTIATE_TEST_CASE_P(
     MAYBE_ZipFiles, /* zip_files.js */
diff --git a/chrome/browser/chromeos/file_manager/path_util.cc b/chrome/browser/chromeos/file_manager/path_util.cc
index e418f5165..1243149 100644
--- a/chrome/browser/chromeos/file_manager/path_util.cc
+++ b/chrome/browser/chromeos/file_manager/path_util.cc
@@ -182,14 +182,29 @@
 std::string ConvertFileSystemURLToPathInsideCrostini(
     Profile* profile,
     const storage::FileSystemURL& file_system_url) {
+  std::string id(file_system_url.mount_filesystem_id());
+  std::string mount_point_name_crostini = GetCrostiniMountPointName(profile);
+  std::string mount_point_name_downloads = GetDownloadsMountPointName(profile);
   DCHECK(file_system_url.mount_type() == storage::kFileSystemTypeExternal);
   DCHECK(file_system_url.type() == storage::kFileSystemTypeNativeLocal);
+  DCHECK(id == mount_point_name_crostini || id == mount_point_name_downloads);
 
-  // Reformat virtual_path()
-  // from <mount_label>/path/to/file
-  // to   /<home-directory>/path/to/file
-  base::FilePath folder(util::GetCrostiniMountPointName(profile));
-  base::FilePath result = HomeDirectoryForProfile(profile);
+  // Reformat virtual_path() from:
+  //   <mount_label>/path/to/file
+  // To either:
+  //   /<home-directory>/path/to/file     (path is already in crostini volume)
+  //   /ChromeOS/<volume_id>/path/to/file (path is shared with crostini)
+  base::FilePath result;
+  base::FilePath folder;
+  if (id == mount_point_name_crostini) {
+    folder = base::FilePath(mount_point_name_crostini);
+    result = ContainerHomeDirectoryForProfile(profile);
+  } else if (id == mount_point_name_downloads) {
+    folder = base::FilePath(mount_point_name_downloads);
+    result = ContainerChromeOSBaseDirectory().Append(kDownloadsFolderName);
+  } else {
+    NOTREACHED();
+  }
   bool success =
       folder.AppendRelativePath(file_system_url.virtual_path(), &result);
   DCHECK(success);
diff --git a/chrome/browser/chromeos/file_manager/path_util_unittest.cc b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
index c11375b89..306ffa4 100644
--- a/chrome/browser/chromeos/file_manager/path_util_unittest.cc
+++ b/chrome/browser/chromeos/file_manager/path_util_unittest.cc
@@ -49,9 +49,9 @@
 TEST(FileManagerPathUtilTest, GetDownloadLocationText) {
   content::TestBrowserThreadBundle thread_bundle;
   content::TestServiceManagerContext service_manager_context;
-  TestingProfileManager profile_manager(TestingBrowserProcess::GetGlobal());
 
   TestingProfile profile(base::FilePath("/home/chronos/u-0123456789abcdef"));
+
   EXPECT_EQ("Downloads",
             GetDownloadLocationText(&profile, "/home/chronos/user/Downloads"));
   EXPECT_EQ("Downloads",
@@ -148,6 +148,33 @@
       &path));
 }
 
+TEST(FileManagerPathUtilTest, ConvertFileSystemURLToPathInsideCrostini) {
+  content::TestBrowserThreadBundle thread_bundle;
+
+  TestingProfile profile;
+  storage::ExternalMountPoints* mount_points =
+      storage::ExternalMountPoints::GetSystemInstance();
+
+  // Register crostini and downloads.
+  mount_points->RegisterFileSystem(
+      GetCrostiniMountPointName(&profile), storage::kFileSystemTypeNativeLocal,
+      storage::FileSystemMountOption(), GetCrostiniMountDirectory(&profile));
+  mount_points->RegisterFileSystem(
+      GetDownloadsMountPointName(&profile), storage::kFileSystemTypeNativeLocal,
+      storage::FileSystemMountOption(), GetDownloadsFolderForProfile(&profile));
+
+  EXPECT_EQ("/home/testing_profile/path/in/crostini",
+            ConvertFileSystemURLToPathInsideCrostini(
+                &profile, mount_points->CreateExternalFileSystemURL(
+                              GURL(), "crostini_test_termina_penguin",
+                              base::FilePath("path/in/crostini"))));
+  EXPECT_EQ("/ChromeOS/Downloads/path/in/downloads",
+            ConvertFileSystemURLToPathInsideCrostini(
+                &profile,
+                mount_points->CreateExternalFileSystemURL(
+                    GURL(), "Downloads", base::FilePath("path/in/downloads"))));
+}
+
 std::unique_ptr<KeyedService> CreateFileSystemOperationRunnerForTesting(
     content::BrowserContext* context) {
   return arc::ArcFileSystemOperationRunner::CreateForTesting(
diff --git a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
index ff9e7a5..c0be25b4 100644
--- a/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
+++ b/chrome/browser/chromeos/login/oobe_interactive_ui_test.cc
@@ -264,7 +264,8 @@
   DISALLOW_COPY_AND_ASSIGN(OobeInteractiveUITest);
 };
 
-IN_PROC_BROWSER_TEST_F(OobeInteractiveUITest, SimpleEndToEnd) {
+// crbug.com/891484
+IN_PROC_BROWSER_TEST_F(OobeInteractiveUITest, DISABLED_SimpleEndToEnd) {
   WaitForOobeWelcomeScreen();
   RunWelcomeScreenChecks();
   TapWelcomeNext();
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 7eaeb8e..a83f91f 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -84,6 +84,7 @@
 #include "chrome/browser/chromeos/system/timezone_util.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/metrics/metrics_reporting_state.h"
+#include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
@@ -275,9 +276,18 @@
   return true;
 }
 
-// Return true if the feature flag for recommend app screen is on.
+// Return false if the logged in user is a managed or child account. Otherwise,
+// return true if the feature flag for recommend app screen is on.
 bool ShouldShowRecommendAppsScreen() {
-  return base::FeatureList::IsEnabled(features::kOobeRecommendAppsScreen);
+  const user_manager::UserManager* user_manager =
+      user_manager::UserManager::Get();
+  DCHECK(user_manager->IsUserLoggedIn());
+  bool is_managed_account =
+      policy::ProfilePolicyConnectorFactory::IsProfileManaged(
+          ProfileManager::GetActiveUserProfile());
+  bool is_child_account = user_manager->IsLoggedInAsChildUser();
+  return !is_managed_account && !is_child_account &&
+         base::FeatureList::IsEnabled(features::kOobeRecommendAppsScreen);
 }
 
 chromeos::LoginDisplayHost* GetLoginDisplayHost() {
diff --git a/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc
index c5a50e0..9bf16b6 100644
--- a/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc
+++ b/chrome/browser/chromeos/policy/affiliated_cloud_policy_invalidator_unittest.cc
@@ -24,6 +24,7 @@
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "google/cacheinvalidation/include/types.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -77,10 +78,9 @@
   // Set up a CloudPolicyCore backed by a simple CloudPolicyStore that does no
   // signature verification and stores policy in memory.
   FakeCloudPolicyStore store;
-  CloudPolicyCore core(dm_protocol::kChromeDevicePolicyType,
-                       std::string(),
-                       &store,
-                       base::ThreadTaskRunnerHandle::Get());
+  CloudPolicyCore core(dm_protocol::kChromeDevicePolicyType, std::string(),
+                       &store, base::ThreadTaskRunnerHandle::Get(),
+                       network::TestNetworkConnectionTracker::CreateGetter());
 
   // Connect |core|. Expect it to send a registration request. Let the
   // registration succeed.
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
index 9a77229..3efc75d 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
@@ -46,6 +46,7 @@
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
+#include "content/public/browser/network_service_instance.h"
 #include "crypto/sha2.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "url/gurl.h"
@@ -110,10 +111,12 @@
     std::unique_ptr<DeviceCloudPolicyStoreChromeOS> store,
     const scoped_refptr<base::SequencedTaskRunner>& task_runner,
     ServerBackedStateKeysBroker* state_keys_broker)
-    : CloudPolicyManager(dm_protocol::kChromeDevicePolicyType,
-                         std::string(),
-                         store.get(),
-                         task_runner),
+    : CloudPolicyManager(
+          dm_protocol::kChromeDevicePolicyType,
+          std::string(),
+          store.get(),
+          task_runner,
+          base::BindRepeating(&content::GetNetworkConnectionTracker)),
       device_store_(std::move(store)),
       state_keys_broker_(state_keys_broker),
       task_runner_(task_runner),
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
index a684b613..cac309e8 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
@@ -41,6 +41,7 @@
 #include "components/policy/policy_constants.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "url/gurl.h"
 
@@ -142,7 +143,8 @@
       core_(dm_protocol::kChromePublicAccountPolicyType,
             store_->account_id(),
             store_.get(),
-            task_runner),
+            task_runner,
+            base::BindRepeating(&content::GetNetworkConnectionTracker)),
       policy_update_callback_(policy_update_callback),
       resource_cache_task_runner_(resource_cache_task_runner) {
   if (account.type != DeviceLocalAccount::TYPE_ARC_KIOSK_APP) {
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
index 75161268..5681850f 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
@@ -51,6 +51,7 @@
 #include "components/user_manager/known_user.h"
 #include "components/user_manager/user.h"
 #include "components/user_manager/user_manager.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "net/url_request/url_request_context_getter.h"
@@ -119,10 +120,12 @@
     base::OnceClosure fatal_error_callback,
     const AccountId& account_id,
     const scoped_refptr<base::SequencedTaskRunner>& task_runner)
-    : CloudPolicyManager(dm_protocol::kChromeUserPolicyType,
-                         std::string(),
-                         store.get(),
-                         task_runner),
+    : CloudPolicyManager(
+          dm_protocol::kChromeUserPolicyType,
+          std::string(),
+          store.get(),
+          task_runner,
+          base::BindRepeating(content::GetNetworkConnectionTracker)),
       profile_(profile),
       store_(std::move(store)),
       external_data_manager_(std::move(external_data_manager)),
diff --git a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
index 8767d22..bbb7c03 100644
--- a/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
+++ b/chrome/browser/chromeos/printing/cups_print_job_manager_impl.cc
@@ -38,8 +38,8 @@
 
 namespace {
 
-// The rate in milliseconds at which we will poll CUPS for print job updates.
-const int kPollRate = 1000;
+// The rate at which we will poll CUPS for print job updates.
+constexpr base::TimeDelta kPollRate = base::TimeDelta::FromMilliseconds(1000);
 
 // Threshold for giving up on communicating with CUPS.
 const int kRetryMax = 6;
@@ -374,8 +374,7 @@
 
   // Schedule a query of CUPS for print job status with a delay of |delay|.
   void ScheduleQuery(int attempt_count = 1) {
-    const int delay_ms = kPollRate * attempt_count;
-    timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(delay_ms),
+    timer_.Start(FROM_HERE, kPollRate * attempt_count,
                  base::Bind(&CupsPrintJobManagerImpl::PostQuery,
                             weak_ptr_factory_.GetWeakPtr()));
   }
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.cc b/chrome/browser/chromeos/printing/cups_printers_manager.cc
index f2d1fe67d..057e1175 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.cc
@@ -62,8 +62,8 @@
       const std::vector<PrinterDetector::DetectedPrinter>& printers) override;
 
  private:
-  CupsPrintersManagerImpl* parent_;
-  int id_;
+  CupsPrintersManagerImpl* const parent_;
+  const int id_;
   SEQUENCE_CHECKER(sequence_);
   ScopedObserver<PrinterDetector, PrinterDetector::Observer> observer_;
 };
@@ -170,7 +170,7 @@
   void RemoveConfiguredPrinter(const std::string& printer_id) override {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
     auto existing = synced_printers_manager_->GetPrinter(printer_id);
-    if (existing != nullptr) {
+    if (existing) {
       event_tracker_->RecordPrinterRemoved(*existing);
     }
     synced_printers_manager_->RemoveConfiguredPrinter(printer_id);
@@ -345,7 +345,7 @@
   void MaybeRecordInstallation(const Printer& printer,
                                bool is_automatic_installation) {
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
-    if (synced_printers_manager_->GetPrinter(printer.id()) != nullptr) {
+    if (synced_printers_manager_->GetPrinter(printer.id())) {
       // It's just an update, not a new installation, so don't record an event.
       return;
     }
@@ -359,7 +359,7 @@
       const auto* detected = FindDetectedPrinter(printer.id());
       // We should have the full DetectedPrinter.  We
       // can't log the printer if we don't have it.
-      if (detected == nullptr) {
+      if (!detected) {
         LOG(WARNING) << "Failed to find USB printer " << printer.id()
                      << " for installation event logging";
         return;
@@ -419,7 +419,7 @@
       }
       auto it = detected_printer_ppd_references_.find(detected.printer.id());
       if (it != detected_printer_ppd_references_.end()) {
-        if (it->second == nullptr) {
+        if (!it->second) {
           // If the detected printer supports ipp-over-usb and we could not find
           // a ppd for it, then we switch to the ippusb scheme and mark it as
           // autoconf.
@@ -466,7 +466,7 @@
     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_);
     if (IsUsbPrinter(printer)) {
       const auto* detected = FindDetectedPrinter(printer.id());
-      if (detected == nullptr) {
+      if (!detected) {
         LOG(WARNING) << "Failed to find USB printer " << printer.id()
                      << " for abandoned event logging";
         return;
@@ -502,7 +502,7 @@
     if (code == PpdProvider::SUCCESS) {
       // If we got something, populate the entry.  Otherwise let it
       // just remain null.
-      value.reset(new Printer::PpdReference(ref));
+      value = std::make_unique<Printer::PpdReference>(ref);
     }
     RebuildDetectedLists();
   }
@@ -514,7 +514,7 @@
   std::vector<PrinterDetector::DetectedPrinter> zeroconf_detections_;
 
   // Not owned.
-  SyncedPrintersManager* synced_printers_manager_;
+  SyncedPrintersManager* const synced_printers_manager_;
   ScopedObserver<SyncedPrintersManager, SyncedPrintersManager::Observer>
       synced_printers_manager_observer_;
 
@@ -528,14 +528,11 @@
   scoped_refptr<PpdProvider> ppd_provider_;
 
   // Not owned
-  PrinterEventTracker* event_tracker_;
+  PrinterEventTracker* const event_tracker_;
 
   // Categorized printers.  This is indexed by PrinterClass.
   std::vector<std::vector<Printer>> printers_;
 
-  // Printer ids that occur in one of our categories or printers.
-  std::unordered_set<std::string> known_printer_ids_;
-
   // This is a dual-purpose structure.  The keys in the map are printer ids.
   // If an entry exists in this map it means we have received a response from
   // PpdProvider about a PpdReference for the given printer.  A null value
@@ -581,7 +578,7 @@
 }
 
 // static
-std::unique_ptr<CupsPrintersManager> CupsPrintersManager::Create(
+std::unique_ptr<CupsPrintersManager> CupsPrintersManager::CreateForTesting(
     SyncedPrintersManager* synced_printers_manager,
     std::unique_ptr<PrinterDetector> usb_detector,
     std::unique_ptr<PrinterDetector> zeroconf_detector,
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.h b/chrome/browser/chromeos/printing/cups_printers_manager.h
index 37369c8..b03ab169 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.h
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.h
@@ -31,7 +31,7 @@
 // in this class must be called from a sequenced context.
 class CupsPrintersManager : public KeyedService {
  public:
-  // Classes of printers tracked.  See doc/cups_printers_management.md for
+  // Classes of printers tracked.  See doc/cups_printer_management.md for
   // details on what these mean.
   enum PrinterClass {
     kConfigured,
@@ -43,10 +43,12 @@
 
   class Observer {
    public:
-    virtual ~Observer() = default;
     // The list of printers in this class has changed to the given printers.
     virtual void OnPrintersChanged(PrinterClass printer_class,
                                    const std::vector<Printer>& printers) = 0;
+
+   protected:
+    virtual ~Observer() = default;
   };
 
   // Factory function.
@@ -54,7 +56,7 @@
 
   // Factory function that allows injected dependencies, for testing.  Ownership
   // is not taken of any of the raw-pointer arguments.
-  static std::unique_ptr<CupsPrintersManager> Create(
+  static std::unique_ptr<CupsPrintersManager> CreateForTesting(
       SyncedPrintersManager* synced_printers_manager,
       std::unique_ptr<PrinterDetector> usb_printer_detector,
       std::unique_ptr<PrinterDetector> zeroconf_printer_detector,
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
index 87fb9df..76f234c 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
@@ -263,7 +263,7 @@
     // Register the pref |UserNativePrintersAllowed|
     CupsPrintersManager::RegisterProfilePrefs(pref_service_.registry());
 
-    manager_ = CupsPrintersManager::Create(
+    manager_ = CupsPrintersManager::CreateForTesting(
         &synced_printers_manager_, std::move(usb_detector),
         std::move(zeroconf_detector), ppd_provider_, &event_tracker_,
         &pref_service_);
diff --git a/chrome/browser/chromeos/printing/synced_printers_manager_unittest.cc b/chrome/browser/chromeos/printing/synced_printers_manager_unittest.cc
index 8292c6d3..ff90a8c 100644
--- a/chrome/browser/chromeos/printing/synced_printers_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/synced_printers_manager_unittest.cc
@@ -261,7 +261,7 @@
   configured.set_display_name("display name");
   manager_->PrinterInstalled(configured);
   auto found_printer = manager_->GetPrinter(kTestPrinterId);
-  ASSERT_FALSE(found_printer == nullptr);
+  ASSERT_TRUE(found_printer);
   EXPECT_TRUE(found_printer->display_name().empty());
 
   // Installing the enterprise printer should *not* generate a configuration
diff --git a/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc b/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc
index 9144fee..0a4c30b 100644
--- a/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc
+++ b/chrome/browser/chromeos/printing/zeroconf_printer_detector.cc
@@ -143,17 +143,14 @@
   printer.set_display_name(metadata.ty);
   printer.set_description(metadata.note);
   printer.set_make_and_model(metadata.product);
+  const std::string service_type = service_description.service_type();
   const char* uri_protocol;
-  if ((service_description.service_type() ==
-       base::StringPiece(ZeroconfPrinterDetector::kIppServiceName)) ||
-      (service_description.service_type() ==
-       base::StringPiece(ZeroconfPrinterDetector::kIppEverywhereServiceName))) {
+  if (service_type == ZeroconfPrinterDetector::kIppServiceName ||
+      service_type == ZeroconfPrinterDetector::kIppEverywhereServiceName) {
     uri_protocol = "ipp";
-  } else if ((service_description.service_type() ==
-              base::StringPiece(ZeroconfPrinterDetector::kIppsServiceName)) ||
-             (service_description.service_type() ==
-              base::StringPiece(
-                  ZeroconfPrinterDetector::kIppsEverywhereServiceName))) {
+  } else if (service_type == ZeroconfPrinterDetector::kIppsServiceName ||
+             service_type ==
+                 ZeroconfPrinterDetector::kIppsEverywhereServiceName) {
     uri_protocol = "ipps";
   } else {
     // Since we only register for these services, we should never get back
@@ -178,8 +175,7 @@
   // (possibly in addition to suffix-free versions).  If we get a printer from a
   // ,_print service type, it should be auto-configurable with IPP Everywhere.
   printer.mutable_ppd_reference()->autoconf =
-      base::StringPiece(service_description.service_type())
-          .ends_with(",_print");
+      base::StringPiece(service_type).ends_with(",_print");
 
   // gather ppd identification candidates.
   if (!metadata.ty.empty()) {
diff --git a/chrome/browser/chromeos/printing/zeroconf_printer_detector_unittest.cc b/chrome/browser/chromeos/printing/zeroconf_printer_detector_unittest.cc
index 27f7329..7719e43 100644
--- a/chrome/browser/chromeos/printing/zeroconf_printer_detector_unittest.cc
+++ b/chrome/browser/chromeos/printing/zeroconf_printer_detector_unittest.cc
@@ -105,38 +105,38 @@
   void OnDeviceChanged(const std::string& service_type,
                        bool added,
                        const ServiceDescription& service_description) override {
-    if (actual_ == nullptr) {
+    if (actual_) {
+      actual_->OnDeviceChanged(service_type, added, service_description);
+    } else {
       deferred_callbacks_.push_back(base::BindOnce(
           &DeferringDelegate::OnDeviceChanged, base::Unretained(this),
           service_type, added, service_description));
-    } else {
-      actual_->OnDeviceChanged(service_type, added, service_description);
     }
   }
   // Not guaranteed to be called after OnDeviceChanged.
   void OnDeviceRemoved(const std::string& service_type,
                        const std::string& service_name) override {
-    if (actual_ == nullptr) {
+    if (actual_) {
+      actual_->OnDeviceRemoved(service_type, service_name);
+    } else {
       deferred_callbacks_.push_back(
           base::BindOnce(&DeferringDelegate::OnDeviceRemoved,
                          base::Unretained(this), service_type, service_name));
-    } else {
-      actual_->OnDeviceRemoved(service_type, service_name);
     }
   }
 
   void OnDeviceCacheFlushed(const std::string& service_type) override {
-    if (actual_ == nullptr) {
+    if (actual_) {
+      actual_->OnDeviceCacheFlushed(service_type);
+    } else {
       deferred_callbacks_.push_back(
           base::BindOnce(&DeferringDelegate::OnDeviceCacheFlushed,
                          base::Unretained(this), service_type));
-    } else {
-      actual_->OnDeviceCacheFlushed(service_type);
     }
   }
 
   void SetActual(ServiceDiscoveryDeviceLister::Delegate* actual) {
-    CHECK(actual_ == nullptr);
+    CHECK(!actual_);
     actual_ = actual;
     for (auto& cb : deferred_callbacks_) {
       std::move(cb).Run();
diff --git a/chrome/browser/content_settings/local_shared_objects_container.cc b/chrome/browser/content_settings/local_shared_objects_container.cc
index 09e6b97..3518af3 100644
--- a/chrome/browser/content_settings/local_shared_objects_container.cc
+++ b/chrome/browser/content_settings/local_shared_objects_container.cc
@@ -88,9 +88,8 @@
   typedef CannedBrowsingDataCookieHelper::OriginCookieSetMap OriginCookieSetMap;
   const OriginCookieSetMap& origin_cookies_set_map =
       cookies()->origin_cookie_set_map();
-  for (OriginCookieSetMap::const_iterator it = origin_cookies_set_map.begin();
-       it != origin_cookies_set_map.end();
-       ++it) {
+  for (auto it = origin_cookies_set_map.begin();
+       it != origin_cookies_set_map.end(); ++it) {
     const canonical_cookie::CookieHashSet* cookie_list = it->second.get();
     for (const auto& cookie : *cookie_list) {
       // Strip leading '.'s.
@@ -111,8 +110,7 @@
   // Count local storages for the domain of the given |origin|.
   const std::set<GURL> local_storage_info =
       local_storages()->GetLocalStorageInfo();
-  for (std::set<GURL>::const_iterator it = local_storage_info.begin();
-       it != local_storage_info.end();
+  for (auto it = local_storage_info.begin(); it != local_storage_info.end();
        ++it) {
     if (SameDomainOrHost(origin, *it))
       ++count;
@@ -120,9 +118,7 @@
 
   // Count session storages for the domain of the given |origin|.
   const std::set<GURL> urls = session_storages()->GetLocalStorageInfo();
-  for (std::set<GURL>::const_iterator it = urls.begin();
-       it != urls.end();
-       ++it) {
+  for (auto it = urls.begin(); it != urls.end(); ++it) {
     if (SameDomainOrHost(origin, *it))
       ++count;
   }
@@ -131,10 +127,7 @@
   typedef CannedBrowsingDataIndexedDBHelper::PendingIndexedDBInfo IndexedDBInfo;
   const std::set<IndexedDBInfo>& indexed_db_info =
       indexed_dbs()->GetIndexedDBInfo();
-  for (std::set<IndexedDBInfo>::const_iterator it =
-          indexed_db_info.begin();
-      it != indexed_db_info.end();
-      ++it) {
+  for (auto it = indexed_db_info.begin(); it != indexed_db_info.end(); ++it) {
     if (SameDomainOrHost(origin, it->origin))
       ++count;
   }
@@ -144,10 +137,8 @@
       ServiceWorkerInfo;
   const std::set<ServiceWorkerInfo>& service_worker_info =
       service_workers()->GetServiceWorkerUsageInfo();
-  for (std::set<ServiceWorkerInfo>::const_iterator it =
-          service_worker_info.begin();
-      it != service_worker_info.end();
-      ++it) {
+  for (auto it = service_worker_info.begin(); it != service_worker_info.end();
+       ++it) {
     if (SameDomainOrHost(origin, it->origin))
       ++count;
   }
@@ -176,9 +167,7 @@
   typedef std::list<FileSystemInfo> FileSystemInfoList;
   const FileSystemInfoList& file_system_info =
       file_systems()->GetFileSystemInfo();
-  for (FileSystemInfoList::const_iterator it = file_system_info.begin();
-       it != file_system_info.end();
-       ++it) {
+  for (auto it = file_system_info.begin(); it != file_system_info.end(); ++it) {
     if (SameDomainOrHost(origin, it->origin))
       ++count;
   }
@@ -187,10 +176,7 @@
   typedef CannedBrowsingDataDatabaseHelper::PendingDatabaseInfo DatabaseInfo;
   const std::set<DatabaseInfo>& database_list =
       databases()->GetPendingDatabaseInfo();
-  for (std::set<DatabaseInfo>::const_iterator it =
-          database_list.begin();
-      it != database_list.end();
-      ++it) {
+  for (auto it = database_list.begin(); it != database_list.end(); ++it) {
     if (SameDomainOrHost(origin, it->origin))
       ++count;
   }
@@ -199,16 +185,11 @@
   typedef BrowsingDataAppCacheHelper::OriginAppCacheInfoMap
       OriginAppCacheInfoMap;
   const OriginAppCacheInfoMap& map = appcaches()->GetOriginAppCacheInfoMap();
-  for (OriginAppCacheInfoMap::const_iterator it = map.begin();
-       it != map.end();
-       ++it) {
+  for (auto it = map.begin(); it != map.end(); ++it) {
     const content::AppCacheInfoVector& info_vector = it->second;
-    for (content::AppCacheInfoVector::const_iterator info =
-             info_vector.begin();
-         info != info_vector.end();
-         ++info) {
-       if (SameDomainOrHost(origin, info->manifest_url))
-         ++count;
+    for (auto info = info_vector.begin(); info != info_vector.end(); ++info) {
+      if (SameDomainOrHost(origin, info->manifest_url))
+        ++count;
     }
   }
 
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry.cc b/chrome/browser/custom_handlers/protocol_handler_registry.cc
index 399c01769..96aba56 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry.cc
@@ -39,8 +39,7 @@
 const ProtocolHandler& LookupHandler(
     const ProtocolHandlerRegistry::ProtocolHandlerMap& handler_map,
     const std::string& scheme) {
-  ProtocolHandlerRegistry::ProtocolHandlerMap::const_iterator p =
-      handler_map.find(scheme);
+  auto p = handler_map.find(scheme);
 
   if (p != handler_map.end())
     return p->second;
@@ -330,8 +329,7 @@
   ProtocolHandlerList to_replace(GetReplacedHandlers(handler));
   if (to_replace.empty())
     return false;
-  for (ProtocolHandlerList::iterator p = to_replace.begin();
-       p != to_replace.end(); ++p) {
+  for (auto p = to_replace.begin(); p != to_replace.end(); ++p) {
     RemoveHandler(*p);
   }
   if (make_new_handler_default) {
@@ -350,8 +348,7 @@
   const ProtocolHandlerList* handlers = GetHandlerList(handler.protocol());
   if (!handlers)
     return replaced_handlers;
-  for (ProtocolHandlerList::const_iterator p = handlers->begin();
-       p != handlers->end(); p++) {
+  for (auto p = handlers->begin(); p != handlers->end(); ++p) {
     if (handler.IsSameOrigin(*p)) {
       replaced_handlers.push_back(*p);
     }
@@ -448,7 +445,7 @@
 ProtocolHandlerRegistry::GetHandlersFor(
     const std::string& scheme) const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
+  auto p = protocol_handlers_.find(scheme);
   if (p == protocol_handlers_.end()) {
     return ProtocolHandlerList();
   }
@@ -618,7 +615,7 @@
     if (!HandlerExists(handler, &policy_protocol_handlers_))
       EraseHandler(handler, &protocol_handlers_);
   }
-  ProtocolHandlerMap::iterator q = default_handlers_.find(handler.protocol());
+  auto q = default_handlers_.find(handler.protocol());
   if (erase_success && q != default_handlers_.end() && q->second == handler) {
     // Make the new top handler in the list the default.
     if (!handlers.empty()) {
@@ -715,8 +712,7 @@
 void ProtocolHandlerRegistry::PromoteHandler(const ProtocolHandler& handler) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(IsRegistered(handler));
-  ProtocolHandlerMultiMap::iterator p =
-      protocol_handlers_.find(handler.protocol());
+  auto p = protocol_handlers_.find(handler.protocol());
   ProtocolHandlerList& list = p->second;
   list.erase(std::find(list.begin(), list.end(), handler));
   list.insert(list.begin(), handler);
@@ -744,7 +740,7 @@
 ProtocolHandlerRegistry::GetHandlerList(
     const std::string& scheme) const {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  ProtocolHandlerMultiMap::const_iterator p = protocol_handlers_.find(scheme);
+  auto p = protocol_handlers_.find(scheme);
   if (p == protocol_handlers_.end()) {
     return NULL;
   }
@@ -769,8 +765,7 @@
 
 void ProtocolHandlerRegistry::InsertHandler(const ProtocolHandler& handler) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  ProtocolHandlerMultiMap::iterator p =
-      protocol_handlers_.find(handler.protocol());
+  auto p = protocol_handlers_.find(handler.protocol());
 
   if (p != protocol_handlers_.end()) {
     p->second.push_back(handler);
@@ -785,11 +780,9 @@
 base::Value* ProtocolHandlerRegistry::EncodeRegisteredHandlers() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::ListValue* protocol_handlers = new base::ListValue();
-  for (ProtocolHandlerMultiMap::iterator i = user_protocol_handlers_.begin();
-       i != user_protocol_handlers_.end();
-       ++i) {
-    for (ProtocolHandlerList::iterator j = i->second.begin();
-         j != i->second.end(); ++j) {
+  for (auto i = user_protocol_handlers_.begin();
+       i != user_protocol_handlers_.end(); ++i) {
+    for (auto j = i->second.begin(); j != i->second.end(); ++j) {
       std::unique_ptr<base::DictionaryValue> encoded = j->Encode();
       if (IsDefault(*j)) {
         encoded->Set("default", std::make_unique<base::Value>(true));
@@ -803,10 +796,8 @@
 base::Value* ProtocolHandlerRegistry::EncodeIgnoredHandlers() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   base::ListValue* handlers = new base::ListValue();
-  for (ProtocolHandlerList::iterator i =
-           user_ignored_protocol_handlers_.begin();
-       i != user_ignored_protocol_handlers_.end();
-       ++i) {
+  for (auto i = user_ignored_protocol_handlers_.begin();
+       i != user_ignored_protocol_handlers_.end(); ++i) {
     handlers->Append(i->Encode());
   }
   return handlers;
diff --git a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
index ac2cb1c..6dc60e1 100644
--- a/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
+++ b/chrome/browser/custom_handlers/protocol_handler_registry_unittest.cc
@@ -272,8 +272,7 @@
 
   int InMemoryHandlerCount() {
     int in_memory_handler_count = 0;
-    ProtocolHandlerRegistry::ProtocolHandlerMultiMap::iterator it =
-        registry()->protocol_handlers_.begin();
+    auto it = registry()->protocol_handlers_.begin();
     for (; it != registry()->protocol_handlers_.end(); ++it)
       in_memory_handler_count += it->second.size();
     return in_memory_handler_count;
@@ -287,8 +286,7 @@
 
   int InMemoryIgnoredHandlerCount() {
     int in_memory_ignored_handler_count = 0;
-    ProtocolHandlerRegistry::ProtocolHandlerList::iterator it =
-        registry()->ignored_protocol_handlers_.begin();
+    auto it = registry()->ignored_protocol_handlers_.begin();
     for (; it != registry()->ignored_protocol_handlers_.end(); ++it)
       in_memory_ignored_handler_count++;
     return in_memory_ignored_handler_count;
diff --git a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
index c145260..a202620 100644
--- a/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
+++ b/chrome/browser/data_use_measurement/chrome_data_use_ascriber.cc
@@ -67,7 +67,7 @@
 
 ChromeDataUseRecorder* ChromeDataUseAscriber::GetOrCreateDataUseRecorder(
     net::URLRequest* request) {
-  DataUseRecorderEntry entry = GetOrCreateDataUseRecorderEntry(request);
+  auto entry = GetOrCreateDataUseRecorderEntry(request);
   return entry == data_use_recorders_.end() ? nullptr : &(*entry);
 }
 
@@ -109,7 +109,7 @@
   DataUseUserData* service = static_cast<DataUseUserData*>(
       request->GetUserData(DataUseUserData::kUserDataKey));
   if (service) {
-    DataUseRecorderEntry entry =
+    auto entry =
         CreateNewDataUseRecorder(request, DataUse::TrafficType::SERVICES);
     entry->data_use().set_description(
         DataUseUserData::GetServiceNameAsString(service->service_name()));
@@ -124,7 +124,7 @@
   if (!request_info ||
       request_info->GetGlobalRequestID() == content::GlobalRequestID()) {
     // Create a new DataUseRecorder for all non-content initiated requests.
-    DataUseRecorderEntry entry =
+    auto entry =
         CreateNewDataUseRecorder(request, DataUse::TrafficType::UNKNOWN);
     DataUse& data_use = entry->data_use();
     data_use.set_url(request->url());
@@ -132,7 +132,7 @@
   }
 
   if (request_info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME) {
-    DataUseRecorderEntry new_entry =
+    auto new_entry =
         CreateNewDataUseRecorder(request, DataUse::TrafficType::USER_TRAFFIC);
     new_entry->set_main_frame_request_id(request_info->GetGlobalRequestID());
     pending_navigation_data_use_map_.insert(
@@ -170,7 +170,7 @@
   }
 
   // Create a new DataUseRecorder for all other requests.
-  DataUseRecorderEntry entry = CreateNewDataUseRecorder(
+  auto entry = CreateNewDataUseRecorder(
       request,
       content::ResourceRequestInfo::OriginatedFromServiceWorker(request)
           ? DataUse::TrafficType::SERVICE_WORKER
@@ -320,7 +320,7 @@
         std::make_pair(render_frame, render_frame));
     DCHECK(main_render_frame_entry_map_.find(render_frame) ==
            main_render_frame_entry_map_.end());
-    DataUseRecorderEntry entry =
+    auto entry =
         CreateNewDataUseRecorder(nullptr, DataUse::TrafficType::USER_TRAFFIC);
     entry->set_main_frame_id(render_frame);
     main_render_frame_entry_map_.emplace(std::piecewise_construct,
@@ -344,7 +344,7 @@
     auto main_frame_it = main_render_frame_entry_map_.find(key);
 
     if (main_render_frame_entry_map_.end() != main_frame_it) {
-      DataUseRecorderEntry entry = main_frame_it->second.data_use_recorder;
+      auto entry = main_frame_it->second.data_use_recorder;
 
       // Stop tracking requests for the old frame.
       std::vector<net::URLRequest*> pending_url_requests;
@@ -473,8 +473,7 @@
     }
     return;
   }
-  DataUseRecorderEntry old_frame_entry =
-      main_frame_it->second.data_use_recorder;
+  auto old_frame_entry = main_frame_it->second.data_use_recorder;
   old_frame_entry->set_page_transition(page_transition);
 
   if (old_frame_entry == entry)
@@ -554,7 +553,7 @@
     return;
 
   // Check that the DataUse entry has a committed URL.
-  DataUseRecorderEntry entry = main_frame_it->second.data_use_recorder;
+  auto entry = main_frame_it->second.data_use_recorder;
   DataUse& data_use = entry->data_use();
   if (data_use.url().is_valid()) {
     NotifyDidFinishLoad(entry);
@@ -586,7 +585,7 @@
 ChromeDataUseAscriber::CreateNewDataUseRecorder(
     net::URLRequest* request,
     DataUse::TrafficType traffic_type) {
-  DataUseRecorderEntry entry =
+  auto entry =
       data_use_recorders_.emplace(data_use_recorders_.end(), traffic_type);
   if (request)
     AscribeRecorderWithRequest(request, entry);
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 1f674f0..9dd69cc 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -731,8 +731,7 @@
     manager->GetAllDownloads(&items);
 
     DownloadItem* new_item = NULL;
-    for (DownloadManager::DownloadVector::iterator iter = items.begin();
-         iter != items.end(); ++iter) {
+    for (auto iter = items.begin(); iter != items.end(); ++iter) {
       if ((*iter)->GetState() == DownloadItem::IN_PROGRESS) {
         // There should be only one IN_PROGRESS item.
         EXPECT_EQ(NULL, new_item);
diff --git a/chrome/browser/download/download_commands.cc b/chrome/browser/download/download_commands.cc
index e827d09..b3e1a24b 100644
--- a/chrome/browser/download/download_commands.cc
+++ b/chrome/browser/download/download_commands.cc
@@ -187,7 +187,7 @@
       learn_more_url, g_browser_process->GetApplicationLocale());
   return net::AppendQueryParameter(
       learn_more_url, "ctx",
-      base::IntToString(static_cast<int>(model_->GetLastReason())));
+      base::IntToString(static_cast<int>(model_->download()->GetLastReason())));
 }
 
 gfx::Image DownloadCommands::GetCommandIcon(Command command) {
diff --git a/chrome/browser/download/download_core_service.cc b/chrome/browser/download/download_core_service.cc
index e5b7b4e1..284fee89 100644
--- a/chrome/browser/download/download_core_service.cc
+++ b/chrome/browser/download/download_core_service.cc
@@ -19,8 +19,7 @@
       g_browser_process->profile_manager()->GetLoadedProfiles());
 
   int count = 0;
-  for (std::vector<Profile*>::iterator it = profiles.begin();
-       it < profiles.end(); ++it) {
+  for (auto it = profiles.begin(); it < profiles.end(); ++it) {
     count += DownloadCoreServiceFactory::GetForBrowserContext(*it)
                  ->NonMaliciousDownloadCount();
     if ((*it)->HasOffTheRecordProfile())
@@ -36,8 +35,7 @@
 void DownloadCoreService::CancelAllDownloads() {
   std::vector<Profile*> profiles(
       g_browser_process->profile_manager()->GetLoadedProfiles());
-  for (std::vector<Profile*>::iterator it = profiles.begin();
-       it < profiles.end(); ++it) {
+  for (auto it = profiles.begin(); it < profiles.end(); ++it) {
     DownloadCoreService* service =
         DownloadCoreServiceFactory::GetForBrowserContext(*it);
     service->CancelDownloads();
diff --git a/chrome/browser/download/download_core_service_impl.cc b/chrome/browser/download/download_core_service_impl.cc
index 230d6b82..b1b3130 100644
--- a/chrome/browser/download/download_core_service_impl.cc
+++ b/chrome/browser/download/download_core_service_impl.cc
@@ -114,8 +114,7 @@
       BrowserContext::GetDownloadManager(profile_);
   DownloadManager::DownloadVector downloads;
   download_manager->GetAllDownloads(&downloads);
-  for (DownloadManager::DownloadVector::iterator it = downloads.begin();
-       it != downloads.end(); ++it) {
+  for (auto it = downloads.begin(); it != downloads.end(); ++it) {
     if ((*it)->GetState() == download::DownloadItem::IN_PROGRESS)
       (*it)->Cancel(false);
   }
diff --git a/chrome/browser/download/download_history_unittest.cc b/chrome/browser/download/download_history_unittest.cc
index 2cc6a5a4..fede8f9 100644
--- a/chrome/browser/download/download_history_unittest.cc
+++ b/chrome/browser/download/download_history_unittest.cc
@@ -97,8 +97,7 @@
 
   void RemoveDownloads(const IdSet& ids) override {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    for (IdSet::const_iterator it = ids.begin();
-         it != ids.end(); ++it) {
+    for (auto it = ids.begin(); it != ids.end(); ++it) {
       remove_downloads_.insert(*it);
     }
   }
@@ -158,8 +157,8 @@
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
     content::RunAllPendingInMessageLoop(content::BrowserThread::UI);
     IdSet differences = base::STLSetDifference<IdSet>(ids, remove_downloads_);
-    for (IdSet::const_iterator different = differences.begin();
-         different != differences.end(); ++different) {
+    for (auto different = differences.begin(); different != differences.end();
+         ++different) {
       EXPECT_TRUE(false) << *different;
     }
     remove_downloads_.clear();
diff --git a/chrome/browser/download/download_item_model.cc b/chrome/browser/download/download_item_model.cc
index 9450df0..3c37462 100644
--- a/chrome/browser/download/download_item_model.cc
+++ b/chrome/browser/download/download_item_model.cc
@@ -465,10 +465,6 @@
   download_->SetOpenWhenComplete(open);
 }
 
-download::DownloadInterruptReason DownloadItemModel::GetLastReason() const {
-  return download_->GetLastReason();
-}
-
 base::FilePath DownloadItemModel::GetFullPath() const {
   return download_->GetFullPath();
 }
@@ -684,6 +680,12 @@
 }
 #endif
 
+offline_items_collection::FailState DownloadItemModel::GetLastFailState()
+    const {
+  return OfflineItemUtils::ConvertDownloadInterruptReasonToFailState(
+      download_->GetLastReason());
+}
+
 std::string DownloadItemModel::GetMimeType() const {
   return download_->GetMimeType();
 }
diff --git a/chrome/browser/download/download_item_model.h b/chrome/browser/download/download_item_model.h
index 624abd3b..7d326552 100644
--- a/chrome/browser/download/download_item_model.h
+++ b/chrome/browser/download/download_item_model.h
@@ -71,12 +71,12 @@
   void Resume() override;
   void Remove() override;
   void SetOpenWhenComplete(bool open) override;
-  download::DownloadInterruptReason GetLastReason() const override;
   base::FilePath GetFullPath() const override;
   bool CanResume() const override;
   bool AllDataSaved() const override;
   bool GetFileExternallyRemoved() const override;
   GURL GetURL() const override;
+  offline_items_collection::FailState GetLastFailState() const override;
 
 #if !defined(OS_ANDROID)
   bool IsCommandEnabled(const DownloadCommands* download_commands,
diff --git a/chrome/browser/download/download_path_reservation_tracker.cc b/chrome/browser/download/download_path_reservation_tracker.cc
index d4df519..8b2329f 100644
--- a/chrome/browser/download/download_path_reservation_tracker.cc
+++ b/chrome/browser/download/download_path_reservation_tracker.cc
@@ -296,7 +296,7 @@
 // associated with |key| to |new_path|.
 void UpdateReservation(ReservationKey key, const base::FilePath& new_path) {
   DCHECK(g_reservation_map != NULL);
-  ReservationMap::iterator iter = g_reservation_map->find(key);
+  auto iter = g_reservation_map->find(key);
   if (iter != g_reservation_map->end()) {
     iter->second = new_path;
   } else {
diff --git a/chrome/browser/download/download_prefs.cc b/chrome/browser/download/download_prefs.cc
index 88a737f1..f21ee39 100644
--- a/chrome/browser/download/download_prefs.cc
+++ b/chrome/browser/download/download_prefs.cc
@@ -436,8 +436,7 @@
 
 void DownloadPrefs::SaveAutoOpenState() {
   std::string extensions;
-  for (AutoOpenSet::iterator it = auto_open_.begin();
-       it != auto_open_.end(); ++it) {
+  for (auto it = auto_open_.begin(); it != auto_open_.end(); ++it) {
 #if defined(OS_POSIX)
     std::string this_extension = *it;
 #elif defined(OS_WIN)
diff --git a/chrome/browser/download/download_query.cc b/chrome/browser/download/download_query.cc
index d768257d..84de546 100644
--- a/chrome/browser/download/download_query.cc
+++ b/chrome/browser/download/download_query.cc
@@ -222,8 +222,7 @@
   base::string16 url_formatted(url_formatter::FormatUrl(item.GetURL()));
   base::string16 path(item.GetTargetFilePath().LossyDisplayName());
 
-  for (std::vector<base::string16>::const_iterator it = query_terms.begin();
-       it != query_terms.end(); ++it) {
+  for (auto it = query_terms.begin(); it != query_terms.end(); ++it) {
     base::string16 term = base::i18n::ToLower(*it);
     if (!base::i18n::StringSearchIgnoringCaseAndAccents(
             term, original_url_raw, NULL, NULL) &&
@@ -319,8 +318,7 @@
 }
 
 bool DownloadQuery::Matches(const DownloadItem& item) const {
-  for (FilterCallbackVector::const_iterator filter = filters_.begin();
-        filter != filters_.end(); ++filter) {
+  for (auto filter = filters_.begin(); filter != filters_.end(); ++filter) {
     if (!filter->Run(item))
       return false;
   }
@@ -378,8 +376,7 @@
 
 bool DownloadQuery::DownloadComparator::operator() (
     const DownloadItem* left, const DownloadItem* right) {
-  for (DownloadQuery::SorterVector::const_iterator term = terms_.begin();
-       term != terms_.end(); ++term) {
+  for (auto term = terms_.begin(); term != terms_.end(); ++term) {
     switch (term->sorter.Run(*left, *right)) {
       case LT: return term->direction == DownloadQuery::ASCENDING;
       case GT: return term->direction == DownloadQuery::DESCENDING;
diff --git a/chrome/browser/download/download_request_limiter.cc b/chrome/browser/download/download_request_limiter.cc
index 995ccd7..2a7f900 100644
--- a/chrome/browser/download/download_request_limiter.cc
+++ b/chrome/browser/download/download_request_limiter.cc
@@ -459,7 +459,7 @@
     content::WebContents* originating_web_contents,
     bool create) {
   DCHECK(web_contents);
-  StateMap::iterator i = state_map_.find(web_contents);
+  auto i = state_map_.find(web_contents);
   if (i != state_map_.end())
     return i->second;
 
diff --git a/chrome/browser/download/download_ui_model.cc b/chrome/browser/download/download_ui_model.cc
index 13bf71c8..a1595668 100644
--- a/chrome/browser/download/download_ui_model.cc
+++ b/chrome/browser/download/download_ui_model.cc
@@ -7,6 +7,7 @@
 #include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
+#include "chrome/browser/download/offline_item_utils.h"
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "net/base/mime_util.h"
@@ -23,188 +24,100 @@
 using base::TimeDelta;
 using download::DownloadItem;
 using safe_browsing::DownloadFileType;
+using offline_items_collection::FailState;
 
 namespace {
 
-base::string16 InterruptReasonStatusMessage(
-    download::DownloadInterruptReason reason) {
-  int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
-
-  switch (reason) {
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_ACCESS_DENIED;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_SAME_AS_SOURCE:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_SAME_AS_SOURCE;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST:
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_ERROR;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
-      string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_CRASH:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_UNAUTHORIZED;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_CERT_PROBLEM;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FORBIDDEN;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_UNREACHABLE;
-      break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CONTENT_LENGTH_MISMATCH;
-      break;
-
-    case download::DOWNLOAD_INTERRUPT_REASON_NONE:
-      NOTREACHED();
-      FALLTHROUGH;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT:
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH:
-      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
-  }
-
-  return l10n_util::GetStringUTF16(string_id);
-}
-
-base::string16 InterruptReasonMessage(
-    download::DownloadInterruptReason reason) {
+// TODO(qinmin): Migrate this description generator to OfflineItemUtils once
+// that component gets used to build desktop UI.
+base::string16 FailStateMessage(FailState fail_state) {
   int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
   base::string16 status_text;
 
-  switch (reason) {
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
+  switch (fail_state) {
+    case FailState::FILE_ACCESS_DENIED:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_ACCESS_DENIED;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
+    case FailState::FILE_NO_SPACE:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_DISK_FULL;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
+    case FailState::FILE_NAME_TOO_LONG:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_PATH_TOO_LONG;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
+    case FailState::FILE_TOO_LARGE:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_LARGE;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
+    case FailState::FILE_VIRUS_INFECTED:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_VIRUS;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
+    case FailState::FILE_TRANSIENT_ERROR:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_TEMPORARY_PROBLEM;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
+    case FailState::FILE_BLOCKED:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_BLOCKED;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
+    case FailState::FILE_SECURITY_CHECK_FAILED:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SECURITY_CHECK_FAILED;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
+    case FailState::FILE_TOO_SHORT:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_TOO_SHORT;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_SAME_AS_SOURCE:
+    case FailState::FILE_SAME_AS_SOURCE:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FILE_SAME_AS_SOURCE;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST:
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
+    case FailState::NETWORK_INVALID_REQUEST:
+    case FailState::NETWORK_FAILED:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_ERROR;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
+    case FailState::NETWORK_TIMEOUT:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_TIMEOUT;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
+    case FailState::NETWORK_DISCONNECTED:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NETWORK_DISCONNECTED;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
+    case FailState::NETWORK_SERVER_DOWN:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_DOWN;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
+    case FailState::SERVER_FAILED:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_PROBLEM;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
+    case FailState::SERVER_BAD_CONTENT:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_NO_FILE;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
+    case FailState::USER_CANCELED:
       string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
+    case FailState::USER_SHUTDOWN:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SHUTDOWN;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_CRASH:
+    case FailState::CRASH:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CRASH;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
+    case FailState::SERVER_UNAUTHORIZED:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNAUTHORIZED;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
+    case FailState::SERVER_CERT_PROBLEM:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_SERVER_CERT_PROBLEM;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN:
+    case FailState::SERVER_FORBIDDEN:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_FORBIDDEN;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE:
+    case FailState::SERVER_UNREACHABLE:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_UNREACHABLE;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH:
+    case FailState::SERVER_CONTENT_LENGTH_MISMATCH:
       string_id = IDS_DOWNLOAD_INTERRUPTED_DESCRIPTION_CONTENT_LENGTH_MISMATCH;
       break;
-    case download::DOWNLOAD_INTERRUPT_REASON_NONE:
+    case FailState::NO_FAILURE:
       NOTREACHED();
       FALLTHROUGH;
     // fallthrough
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
-    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT:
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
-    case download::DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH:
+    case FailState::CANNOT_DOWNLOAD:
+    case FailState::NETWORK_INSTABILITY:
+    case FailState::SERVER_NO_RANGE:
+    case FailState::SERVER_CROSS_ORIGIN_REDIRECT:
+    case FailState::FILE_FAILED:
+    case FailState::FILE_HASH_MISMATCH:
       string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
   }
 
@@ -271,10 +184,10 @@
 
 base::string16 DownloadUIModel::GetInterruptReasonText() const {
   if (GetState() != DownloadItem::INTERRUPTED ||
-      GetLastReason() == download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
+      GetLastFailState() == FailState::USER_CANCELED) {
     return base::string16();
   }
-  return InterruptReasonMessage(GetLastReason());
+  return FailStateMessage(GetLastFailState());
 }
 
 base::string16 DownloadUIModel::GetStatusText() const {
@@ -294,11 +207,12 @@
       status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
       break;
     case DownloadItem::INTERRUPTED: {
-      download::DownloadInterruptReason reason = GetLastReason();
-      if (reason != download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
-        base::string16 interrupt_reason = InterruptReasonStatusMessage(reason);
+      FailState fail_state = GetLastFailState();
+      if (fail_state != FailState::USER_CANCELED) {
+        base::string16 message =
+            OfflineItemUtils::GetFailStateMessage(fail_state);
         status_text = l10n_util::GetStringFUTF16(
-            IDS_DOWNLOAD_STATUS_INTERRUPTED, interrupt_reason);
+            IDS_DOWNLOAD_STATUS_INTERRUPTED, message);
       } else {
         // Same as DownloadItem::CANCELLED.
         status_text = l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
@@ -317,11 +231,11 @@
   base::string16 tooltip = gfx::ElideFilename(
       GetFileNameToReportUser(), font_list, max_width, gfx::Typesetter::NATIVE);
   if (GetState() == DownloadItem::INTERRUPTED &&
-      GetLastReason() != download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
+      GetLastFailState() != FailState::USER_CANCELED) {
     tooltip += base::ASCIIToUTF16("\n");
-    tooltip +=
-        gfx::ElideText(InterruptReasonStatusMessage(GetLastReason()), font_list,
-                       max_width, gfx::ELIDE_TAIL, gfx::Typesetter::NATIVE);
+    tooltip += gfx::ElideText(
+        OfflineItemUtils::GetFailStateMessage(GetLastFailState()), font_list,
+        max_width, gfx::ELIDE_TAIL, gfx::Typesetter::NATIVE);
   }
   return tooltip;
 }
@@ -523,8 +437,8 @@
 
 void DownloadUIModel::SetOpenWhenComplete(bool open) {}
 
-download::DownloadInterruptReason DownloadUIModel::GetLastReason() const {
-  return download::DOWNLOAD_INTERRUPT_REASON_NONE;
+FailState DownloadUIModel::GetLastFailState() const {
+  return FailState::NO_FAILURE;
 }
 
 base::FilePath DownloadUIModel::GetFullPath() const {
diff --git a/chrome/browser/download/download_ui_model.h b/chrome/browser/download/download_ui_model.h
index 12f042a..bcfae334 100644
--- a/chrome/browser/download/download_ui_model.h
+++ b/chrome/browser/download/download_ui_model.h
@@ -257,10 +257,6 @@
   // Marks the download to be auto-opened when completed.
   virtual void SetOpenWhenComplete(bool open);
 
-  // Returns the most recent interrupt reason for this download. Returns
-  // |DOWNLOAD_INTERRUPT_REASON_NONE| if there is no previous interrupt reason.
-  virtual download::DownloadInterruptReason GetLastReason() const;
-
   // Returns the full path to the downloaded or downloading file. This is the
   // path to the physical file, if one exists.
   virtual base::FilePath GetFullPath() const;
@@ -278,6 +274,10 @@
   // Returns the URL represented by this download.
   virtual GURL GetURL() const;
 
+  // Returns the most recent failure reason for this download. Returns
+  // |FailState::NO_FAILURE| if there is no previous failure reason.
+  virtual offline_items_collection::FailState GetLastFailState() const;
+
 #if !defined(OS_ANDROID)
   // Methods related to DownloadCommands.
   // Returns whether the given download command is enabled for this download.
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc
index 0b80f108..0520f00 100644
--- a/chrome/browser/download/notification/download_item_notification.cc
+++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -47,6 +47,7 @@
 #include "ui/message_center/public/cpp/notification.h"
 
 using base::UserMetricsAction;
+using offline_items_collection::FailState;
 
 namespace {
 
@@ -373,10 +374,8 @@
 
   if (item_->GetState() == download::DownloadItem::CANCELLED) {
     // Confirms that a download is cancelled by user action.
-    DCHECK(item_->GetLastReason() ==
-               download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED ||
-           item_->GetLastReason() ==
-               download::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN);
+    DCHECK(item_->GetLastFailState() == FailState::USER_CANCELED ||
+           item_->GetLastFailState() == FailState::USER_SHUTDOWN);
 
     CloseNotification();
     return;
@@ -778,8 +777,8 @@
       // "Cancelled"
       return l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CANCELLED);
     case download::DownloadItem::INTERRUPTED: {
-      download::DownloadInterruptReason reason = item_->GetLastReason();
-      if (reason != download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED) {
+      FailState fail_state = item_->GetLastFailState();
+      if (fail_state != FailState::USER_CANCELED) {
         // "Failed - <REASON>"
         base::string16 interrupt_reason = item_->GetInterruptReasonText();
         DCHECK(!interrupt_reason.empty());
diff --git a/chrome/browser/download/offline_item_model.cc b/chrome/browser/download/offline_item_model.cc
index 258ff97..e054755 100644
--- a/chrome/browser/download/offline_item_model.cc
+++ b/chrome/browser/download/offline_item_model.cc
@@ -187,19 +187,6 @@
   return false;
 }
 
-download::DownloadInterruptReason OfflineItemModel::GetLastReason() const {
-  if (!offline_item_ || offline_item_->state == OfflineItemState::CANCELLED)
-    return download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED;
-  switch (offline_item_->fail_state) {
-    case FailState::CANNOT_DOWNLOAD:
-      return download::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED;
-    case FailState::NETWORK_INSTABILITY:
-      return download::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED;
-    case FailState::NO_FAILURE:
-      return download::DOWNLOAD_INTERRUPT_REASON_NONE;
-  }
-}
-
 base::FilePath OfflineItemModel::GetFullPath() const {
   return GetTargetFilePath();
 }
@@ -245,6 +232,10 @@
     obs.OnDownloadUpdated();
 }
 
+FailState OfflineItemModel::GetLastFailState() const {
+  return offline_item_ ? offline_item_->fail_state : FailState::USER_CANCELED;
+}
+
 #if !defined(OS_ANDROID)
 bool OfflineItemModel::IsCommandEnabled(
     const DownloadCommands* download_commands,
diff --git a/chrome/browser/download/offline_item_model.h b/chrome/browser/download/offline_item_model.h
index d2d47dc..ffc93dd 100644
--- a/chrome/browser/download/offline_item_model.h
+++ b/chrome/browser/download/offline_item_model.h
@@ -50,13 +50,13 @@
   bool IsPaused() const override;
   bool TimeRemaining(base::TimeDelta* remaining) const override;
   bool IsDone() const override;
-  download::DownloadInterruptReason GetLastReason() const override;
   base::FilePath GetFullPath() const override;
   bool CanResume() const override;
   bool AllDataSaved() const override;
   bool GetFileExternallyRemoved() const override;
   GURL GetURL() const override;
   bool ShouldRemoveFromShelfWhenComplete() const override;
+  offline_items_collection::FailState GetLastFailState() const override;
 
 #if !defined(OS_ANDROID)
   bool IsCommandEnabled(const DownloadCommands* download_commands,
diff --git a/chrome/browser/download/offline_item_utils.cc b/chrome/browser/download/offline_item_utils.cc
index 5aadb2a..b7d8333a 100644
--- a/chrome/browser/download/offline_item_utils.cc
+++ b/chrome/browser/download/offline_item_utils.cc
@@ -4,9 +4,11 @@
 
 #include "chrome/browser/download/offline_item_utils.h"
 
+#include "chrome/grit/generated_resources.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/download_item_utils.h"
 #include "third_party/blink/public/common/mime_util/mime_util.h"
+#include "ui/base/l10n/l10n_util.h"
 
 using DownloadItem = download::DownloadItem;
 using ContentId = offline_items_collection::ContentId;
@@ -15,6 +17,7 @@
 using OfflineItemState = offline_items_collection::OfflineItemState;
 using OfflineItemProgressUnit =
     offline_items_collection::OfflineItemProgressUnit;
+using FailState = offline_items_collection::FailState;
 using PendingState = offline_items_collection::PendingState;
 
 namespace {
@@ -91,7 +94,8 @@
   item.time_remaining_ms = time_remaining_known ? time_delta.InMilliseconds()
                                                 : kUnknownRemainingTime;
   // TODO(crbug.com/857549): Add allow_metered, fail_state, pending_state.
-
+  item.fail_state =
+      ConvertDownloadInterruptReasonToFailState(download_item->GetLastReason());
   switch (download_item->GetState()) {
     case DownloadItem::IN_PROGRESS:
       item.state = download_item->IsPaused() ? OfflineItemState::PAUSED
@@ -106,7 +110,8 @@
       item.state = OfflineItemState::CANCELLED;
       break;
     case DownloadItem::INTERRUPTED:
-      item.state = OfflineItemState::INTERRUPTED;
+      item.state = download_item->CanResume() ? OfflineItemState::INTERRUPTED
+                                              : OfflineItemState::FAILED;
       break;
     default:
       NOTREACHED();
@@ -128,3 +133,170 @@
 bool OfflineItemUtils::IsDownload(const ContentId& id) {
   return id.name_space.find(kDownloadNamespacePrefix) != std::string::npos;
 }
+
+// static
+FailState OfflineItemUtils::ConvertDownloadInterruptReasonToFailState(
+    download::DownloadInterruptReason reason) {
+  switch (reason) {
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_FAILED:
+      return FailState::FILE_FAILED;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED:
+      return FailState::FILE_ACCESS_DENIED;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_NO_SPACE:
+      return FailState::FILE_NO_SPACE;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_NAME_TOO_LONG:
+      return FailState::FILE_NAME_TOO_LONG;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_LARGE:
+      return FailState::FILE_TOO_LARGE;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_VIRUS_INFECTED:
+      return FailState::FILE_VIRUS_INFECTED;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR:
+      return FailState::FILE_TRANSIENT_ERROR;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_BLOCKED:
+      return FailState::FILE_BLOCKED;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_SECURITY_CHECK_FAILED:
+      return FailState::FILE_SECURITY_CHECK_FAILED;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_TOO_SHORT:
+      return FailState::FILE_TOO_SHORT;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_HASH_MISMATCH:
+      return FailState::FILE_HASH_MISMATCH;
+    case download::DOWNLOAD_INTERRUPT_REASON_FILE_SAME_AS_SOURCE:
+      return FailState::FILE_SAME_AS_SOURCE;
+    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED:
+      return FailState::NETWORK_FAILED;
+    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT:
+      return FailState::NETWORK_TIMEOUT;
+    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED:
+      return FailState::NETWORK_DISCONNECTED;
+    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_SERVER_DOWN:
+      return FailState::NETWORK_SERVER_DOWN;
+    case download::DOWNLOAD_INTERRUPT_REASON_NETWORK_INVALID_REQUEST:
+      return FailState::NETWORK_INVALID_REQUEST;
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED:
+      return FailState::SERVER_FAILED;
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_NO_RANGE:
+      return FailState::SERVER_NO_RANGE;
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT:
+      return FailState::SERVER_BAD_CONTENT;
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNAUTHORIZED:
+      return FailState::SERVER_UNAUTHORIZED;
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CERT_PROBLEM:
+      return FailState::SERVER_CERT_PROBLEM;
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN:
+      return FailState::SERVER_FORBIDDEN;
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE:
+      return FailState::SERVER_UNREACHABLE;
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CONTENT_LENGTH_MISMATCH:
+      return FailState::SERVER_CONTENT_LENGTH_MISMATCH;
+    case download::DOWNLOAD_INTERRUPT_REASON_SERVER_CROSS_ORIGIN_REDIRECT:
+      return FailState::SERVER_CROSS_ORIGIN_REDIRECT;
+    case download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED:
+      return FailState::USER_CANCELED;
+    case download::DOWNLOAD_INTERRUPT_REASON_USER_SHUTDOWN:
+      return FailState::USER_SHUTDOWN;
+    case download::DOWNLOAD_INTERRUPT_REASON_CRASH:
+      return FailState::CRASH;
+    case download::DOWNLOAD_INTERRUPT_REASON_NONE:
+      return FailState::NO_FAILURE;
+  }
+}
+
+// static
+base::string16 OfflineItemUtils::GetFailStateMessage(FailState fail_state) {
+  int string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
+
+  switch (fail_state) {
+    case FailState::FILE_ACCESS_DENIED:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_ACCESS_DENIED;
+      break;
+    case FailState::FILE_NO_SPACE:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_DISK_FULL;
+      break;
+    case FailState::FILE_NAME_TOO_LONG:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_PATH_TOO_LONG;
+      break;
+    case FailState::FILE_TOO_LARGE:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_LARGE;
+      break;
+    case FailState::FILE_VIRUS_INFECTED:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_VIRUS;
+      break;
+    case FailState::FILE_TRANSIENT_ERROR:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_TEMPORARY_PROBLEM;
+      break;
+    case FailState::FILE_BLOCKED:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_BLOCKED;
+      break;
+    case FailState::FILE_SECURITY_CHECK_FAILED:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SECURITY_CHECK_FAILED;
+      break;
+    case FailState::FILE_TOO_SHORT:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_TOO_SHORT;
+      break;
+    case FailState::FILE_SAME_AS_SOURCE:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FILE_SAME_AS_SOURCE;
+      break;
+    case FailState::NETWORK_INVALID_REQUEST:
+      FALLTHROUGH;
+    case FailState::NETWORK_FAILED:
+      FALLTHROUGH;
+    case FailState::NETWORK_INSTABILITY:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_ERROR;
+      break;
+    case FailState::NETWORK_TIMEOUT:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_TIMEOUT;
+      break;
+    case FailState::NETWORK_DISCONNECTED:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NETWORK_DISCONNECTED;
+      break;
+    case FailState::NETWORK_SERVER_DOWN:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_DOWN;
+      break;
+    case FailState::SERVER_FAILED:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_PROBLEM;
+      break;
+    case FailState::SERVER_BAD_CONTENT:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_NO_FILE;
+      break;
+    case FailState::USER_CANCELED:
+      string_id = IDS_DOWNLOAD_STATUS_CANCELLED;
+      break;
+    case FailState::USER_SHUTDOWN:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SHUTDOWN;
+      break;
+    case FailState::CRASH:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CRASH;
+      break;
+    case FailState::SERVER_UNAUTHORIZED:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_UNAUTHORIZED;
+      break;
+    case FailState::SERVER_CERT_PROBLEM:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_SERVER_CERT_PROBLEM;
+      break;
+    case FailState::SERVER_FORBIDDEN:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_FORBIDDEN;
+      break;
+    case FailState::SERVER_UNREACHABLE:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_UNREACHABLE;
+      break;
+    case FailState::SERVER_CONTENT_LENGTH_MISMATCH:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS_CONTENT_LENGTH_MISMATCH;
+      break;
+
+    case FailState::NO_FAILURE:
+      NOTREACHED();
+      FALLTHROUGH;
+    case FailState::CANNOT_DOWNLOAD:
+      FALLTHROUGH;
+    case FailState::SERVER_NO_RANGE:
+      FALLTHROUGH;
+    case FailState::SERVER_CROSS_ORIGIN_REDIRECT:
+      FALLTHROUGH;
+    case FailState::FILE_FAILED:
+      FALLTHROUGH;
+    case FailState::FILE_HASH_MISMATCH:
+      string_id = IDS_DOWNLOAD_INTERRUPTED_STATUS;
+  }
+
+  return l10n_util::GetStringUTF16(string_id);
+}
diff --git a/chrome/browser/download/offline_item_utils.h b/chrome/browser/download/offline_item_utils.h
index a72f857..2eeb3d6b 100644
--- a/chrome/browser/download/offline_item_utils.h
+++ b/chrome/browser/download/offline_item_utils.h
@@ -9,6 +9,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/strings/string16.h"
 #include "components/download/public/common/download_item.h"
 #include "components/offline_items_collection/core/offline_item.h"
 
@@ -23,6 +24,15 @@
 
   static bool IsDownload(const offline_items_collection::ContentId& id);
 
+  // Converts DownloadInterruptReason to offline_items_collection::FailState.
+  static offline_items_collection::FailState
+  ConvertDownloadInterruptReasonToFailState(
+      download::DownloadInterruptReason reason);
+
+  // Gets the short text to display for a offline_items_collection::FailState.
+  static base::string16 GetFailStateMessage(
+      offline_items_collection::FailState fail_state);
+
  private:
   DISALLOW_COPY_AND_ASSIGN(OfflineItemUtils);
 };
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 8b987f6..abdd74a 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -403,8 +403,6 @@
     "api/web_navigation/web_navigation_api_constants.h",
     "api/web_navigation/web_navigation_api_helpers.cc",
     "api/web_navigation/web_navigation_api_helpers.h",
-    "api/web_request/chrome_extension_web_request_event_router_delegate.cc",
-    "api/web_request/chrome_extension_web_request_event_router_delegate.h",
     "api/web_view/chrome_web_view_internal_api.cc",
     "api/web_view/chrome_web_view_internal_api.h",
     "api/webrtc_audio_private/webrtc_audio_private_api.cc",
diff --git a/chrome/browser/extensions/activity_log/activity_log.cc b/chrome/browser/extensions/activity_log/activity_log.cc
index cbd3105e..12d5470 100644
--- a/chrome/browser/extensions/activity_log/activity_log.cc
+++ b/chrome/browser/extensions/activity_log/activity_log.cc
@@ -177,8 +177,7 @@
   // pointer to the record, or NULL if no such record was found.
   const ApiInfo* Lookup(Action::ActionType action_type,
                         const std::string& api_name) const {
-    std::map<std::string, const ApiInfo*>::const_iterator i =
-        api_database_.find(api_name);
+    auto i = api_database_.find(api_name);
     if (i == api_database_.end())
       return NULL;
     if (i->second->action_type != action_type)
@@ -751,8 +750,7 @@
   if (!is_active_)
     return;
   ExtensionRegistry* registry = ExtensionRegistry::Get(profile_);
-  for (ExecutingScriptsMap::const_iterator it = extension_ids.begin();
-       it != extension_ids.end(); ++it) {
+  for (auto it = extension_ids.begin(); it != extension_ids.end(); ++it) {
     const Extension* extension =
         registry->GetExtensionById(it->first, ExtensionRegistry::ENABLED);
     if (!extension || ActivityLogAPI::IsExtensionWhitelisted(extension->id()))
@@ -777,9 +775,7 @@
       if (prerender_manager &&
           prerender_manager->IsWebContentsPrerendering(web_contents, NULL))
         action->mutable_other()->SetBoolean(constants::kActionPrerender, true);
-      for (std::set<std::string>::const_iterator it2 = it->second.begin();
-           it2 != it->second.end();
-           ++it2) {
+      for (auto it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
         action->mutable_args()->AppendString(*it2);
       }
       LogAction(action);
@@ -823,8 +819,7 @@
     return;
 
   std::vector<GURL> urls;
-  for (std::set<GURL>::const_iterator it = restrict_urls.begin();
-       it != restrict_urls.end(); ++it) {
+  for (auto it = restrict_urls.begin(); it != restrict_urls.end(); ++it) {
     urls.push_back(*it);
   }
   database_policy_->RemoveURLs(urls);
diff --git a/chrome/browser/extensions/activity_log/counting_policy.cc b/chrome/browser/extensions/activity_log/counting_policy.cc
index 210c0936..34454c4 100644
--- a/chrome/browser/extensions/activity_log/counting_policy.cc
+++ b/chrome/browser/extensions/activity_log/counting_policy.cc
@@ -215,7 +215,7 @@
       activity_database()->AdviseFlush(ActivityDatabase::kFlushImmediately);
     queued_actions_date_ = new_date;
 
-    ActionQueue::iterator queued_entry = queued_actions_.find(action);
+    auto queued_entry = queued_actions_.find(action);
     if (queued_entry == queued_actions_.end()) {
       queued_actions_[action] = 1;
     } else {
@@ -284,7 +284,7 @@
   locate_str += " ORDER BY time DESC LIMIT 1";
   insert_str += ")";
 
-  for (ActionQueue::iterator i = queue.begin(); i != queue.end(); ++i) {
+  for (auto i = queue.begin(); i != queue.end(); ++i) {
     const Action& action = *i->first;
     int count = i->second;
 
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index a117e62..aeae67fe 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/strings/string_util.h"
+#include "base/task/post_task.h"
 #include "build/build_config.h"
 #include "chrome/browser/data_use_measurement/data_use_web_contents_observer.h"
 #include "chrome/browser/extensions/api/chrome_device_permissions_prompt.h"
@@ -23,8 +24,8 @@
 #include "chrome/browser/extensions/api/networking_cast_private/chrome_networking_cast_private_delegate.h"
 #include "chrome/browser/extensions/api/storage/managed_value_store_cache.h"
 #include "chrome/browser/extensions/api/storage/sync_value_store_cache.h"
-#include "chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
+#include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/favicon/favicon_utils.h"
 #include "chrome/browser/guest_view/app_view/chrome_app_view_guest_delegate.h"
 #include "chrome/browser/guest_view/chrome_guest_view_manager_delegate.h"
@@ -39,9 +40,13 @@
 #include "components/pdf/browser/pdf_web_contents_helper.h"
 #include "components/signin/core/browser/signin_header_helper.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
 #include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
 #include "extensions/browser/guest_view/web_view/web_view_permission_helper.h"
 #include "google_apis/gaia/gaia_urls.h"
@@ -139,6 +144,53 @@
   return is_sensitive_request;
 }
 
+void ChromeExtensionsAPIClient::NotifyWebRequestWithheld(
+    int render_process_id,
+    int render_frame_id,
+    const ExtensionId& extension_id) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+  auto notify_web_request_withheld_on_ui = [](int render_process_id,
+                                              int render_frame_id,
+                                              const ExtensionId& extension_id) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    // Track down the ExtensionActionRunner and the extension. Since this is
+    // asynchronous, we could hit a null anywhere along the path.
+    content::RenderFrameHost* rfh =
+        content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+    if (!rfh)
+      return;
+    // We don't count subframe blocked actions as yet, since there's no way to
+    // surface this to the user. Ignore these (which is also what we do for
+    // content scripts).
+    if (rfh->GetParent())
+      return;
+    content::WebContents* web_contents =
+        content::WebContents::FromRenderFrameHost(rfh);
+    if (!web_contents)
+      return;
+    extensions::ExtensionActionRunner* runner =
+        extensions::ExtensionActionRunner::GetForWebContents(web_contents);
+    if (!runner)
+      return;
+
+    const extensions::Extension* extension =
+        extensions::ExtensionRegistry::Get(web_contents->GetBrowserContext())
+            ->enabled_extensions()
+            .GetByID(extension_id);
+    if (!extension)
+      return;
+
+    runner->OnWebRequestBlocked(extension);
+  };
+
+  base::PostTaskWithTraits(
+      FROM_HERE, {content::BrowserThread::UI},
+      base::BindOnce(std::move(notify_web_request_withheld_on_ui),
+                     render_process_id, render_frame_id, extension_id));
+}
+
 AppViewGuestDelegate* ChromeExtensionsAPIClient::CreateAppViewGuestDelegate()
     const {
   return new ChromeAppViewGuestDelegate();
@@ -173,11 +225,6 @@
   return new ChromeWebViewPermissionHelperDelegate(web_view_permission_helper);
 }
 
-std::unique_ptr<WebRequestEventRouterDelegate>
-ChromeExtensionsAPIClient::CreateWebRequestEventRouterDelegate() const {
-  return std::make_unique<ChromeExtensionWebRequestEventRouterDelegate>();
-}
-
 scoped_refptr<ContentRulesRegistry>
 ChromeExtensionsAPIClient::CreateContentRulesRegistry(
     content::BrowserContext* browser_context,
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chrome/browser/extensions/api/chrome_extensions_api_client.h
index a99acde..61936f76 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -34,6 +34,9 @@
                                 const std::string& header_name) const override;
   bool ShouldHideBrowserNetworkRequest(
       const WebRequestInfo& request) const override;
+  void NotifyWebRequestWithheld(int render_process_id,
+                                int render_frame_id,
+                                const ExtensionId& extension_id) override;
   AppViewGuestDelegate* CreateAppViewGuestDelegate() const override;
   ExtensionOptionsGuestDelegate* CreateExtensionOptionsGuestDelegate(
       ExtensionOptionsGuest* guest) const override;
@@ -47,8 +50,6 @@
       WebViewGuest* web_view_guest) const override;
   WebViewPermissionHelperDelegate* CreateWebViewPermissionHelperDelegate(
       WebViewPermissionHelper* web_view_permission_helper) const override;
-  std::unique_ptr<WebRequestEventRouterDelegate>
-  CreateWebRequestEventRouterDelegate() const override;
   scoped_refptr<ContentRulesRegistry> CreateContentRulesRegistry(
       content::BrowserContext* browser_context,
       RulesCacheDelegate* cache_delegate) const override;
diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc
index 61abfaf..2787346 100644
--- a/chrome/browser/extensions/api/tabs/tabs_test.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_test.cc
@@ -28,6 +28,7 @@
 #include "chrome/browser/extensions/extension_function_test_utils.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/pdf/pdf_extension_test_util.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
@@ -2074,6 +2075,18 @@
   ui_test_utils::NavigateToURLWithDisposition(
       browser(), url, WindowOpenDisposition::CURRENT_TAB,
       ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
+
+  bool load_success =
+      pdf_extension_test_util::EnsurePDFHasLoaded(second_web_contents);
+  EXPECT_TRUE(load_success);
+
+  // The actual PDF page coordinates that this click goes to is (346, 333),
+  // after several space transformations, not (400, 400). This clicks on a link
+  // to "http://www.facebook.com:83".
+  content::SimulateMouseClickAt(second_web_contents, 0,
+                                blink::WebMouseEvent::Button::kLeft,
+                                gfx::Point(400, 400));
+
   EXPECT_TRUE(navigation_manager.WaitForRequestStart());
 
   browser()->tab_strip_model()->ActivateTabAt(0, true);
diff --git a/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.cc b/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.cc
deleted file mode 100644
index 57ca0bb3..0000000
--- a/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.h"
-
-#include "base/task/post_task.h"
-#include "chrome/browser/extensions/extension_action_runner.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/web_contents.h"
-#include "extensions/browser/extension_registry.h"
-
-namespace {
-
-void NotifyWebRequestWithheldOnUI(int render_process_id,
-                                  int render_frame_id,
-                                  const std::string& extension_id) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  // Track down the ExtensionActionRunner and the extension. Since this is
-  // asynchronous, we could hit a null anywhere along the path.
-  content::RenderFrameHost* rfh =
-      content::RenderFrameHost::FromID(render_process_id, render_frame_id);
-  if (!rfh)
-    return;
-  // We don't count subframe blocked actions as yet, since there's no way to
-  // surface this to the user. Ignore these (which is also what we do for
-  // content scripts).
-  if (rfh->GetParent())
-    return;
-  content::WebContents* web_contents =
-      content::WebContents::FromRenderFrameHost(rfh);
-  if (!web_contents)
-    return;
-  extensions::ExtensionActionRunner* runner =
-      extensions::ExtensionActionRunner::GetForWebContents(web_contents);
-  if (!runner)
-    return;
-
-  const extensions::Extension* extension =
-      extensions::ExtensionRegistry::Get(web_contents->GetBrowserContext())
-          ->enabled_extensions()
-          .GetByID(extension_id);
-  if (!extension)
-    return;
-
-  runner->OnWebRequestBlocked(extension);
-}
-
-}  // namespace
-
-ChromeExtensionWebRequestEventRouterDelegate::
-    ChromeExtensionWebRequestEventRouterDelegate() {
-}
-
-ChromeExtensionWebRequestEventRouterDelegate::
-    ~ChromeExtensionWebRequestEventRouterDelegate() {
-}
-
-void ChromeExtensionWebRequestEventRouterDelegate::NotifyWebRequestWithheld(
-    int render_process_id,
-    int render_frame_id,
-    const std::string& extension_id) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  base::PostTaskWithTraits(
-      FROM_HERE, {content::BrowserThread::UI},
-      base::BindOnce(&NotifyWebRequestWithheldOnUI, render_process_id,
-                     render_frame_id, extension_id));
-}
diff --git a/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.h b/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.h
deleted file mode 100644
index b914a5a..0000000
--- a/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_EXTENSIONS_API_WEB_REQUEST_CHROME_EXTENSION_WEB_REQUEST_EVENT_ROUTER_DELEGATE_H_
-#define CHROME_BROWSER_EXTENSIONS_API_WEB_REQUEST_CHROME_EXTENSION_WEB_REQUEST_EVENT_ROUTER_DELEGATE_H_
-
-#include <memory>
-
-#include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
-
-class ChromeExtensionWebRequestEventRouterDelegate
-    : public extensions::WebRequestEventRouterDelegate {
- public:
-  ChromeExtensionWebRequestEventRouterDelegate();
-  ~ChromeExtensionWebRequestEventRouterDelegate() override;
-
-  void NotifyWebRequestWithheld(int render_process_id,
-                                int render_frame_id,
-                                const std::string& extension_id) override;
-};
-
-#endif  // CHROME_BROWSER_EXTENSIONS_API_WEB_REQUEST_CHROME_EXTENSION_WEB_REQUEST_EVENT_ROUTER_DELEGATE_H_
diff --git a/chrome/browser/extensions/chrome_app_icon_loader.cc b/chrome/browser/extensions/chrome_app_icon_loader.cc
index 99b3ed02..2126fd80 100644
--- a/chrome/browser/extensions/chrome_app_icon_loader.cc
+++ b/chrome/browser/extensions/chrome_app_icon_loader.cc
@@ -75,7 +75,7 @@
 }
 
 void ChromeAppIconLoader::UpdateImage(const std::string& id) {
-  ExtensionIDToChromeAppIconMap::iterator it = map_.find(id);
+  auto it = map_.find(id);
   if (it == map_.end())
     return;
 
diff --git a/chrome/browser/extensions/chrome_app_icon_service.cc b/chrome/browser/extensions/chrome_app_icon_service.cc
index ff8b3e3..56784ee 100644
--- a/chrome/browser/extensions/chrome_app_icon_service.cc
+++ b/chrome/browser/extensions/chrome_app_icon_service.cc
@@ -93,7 +93,7 @@
 
 void ChromeAppIconService::OnIconDestroyed(ChromeAppIcon* icon) {
   DCHECK(icon);
-  IconMap::iterator it = icon_map_.find(icon->app_id());
+  auto it = icon_map_.find(icon->app_id());
   DCHECK(it != icon_map_.end());
   it->second.erase(icon);
   if (it->second.empty()) {
@@ -105,7 +105,7 @@
 }
 
 void ChromeAppIconService::MaybeCleanupIconSet(const std::string& app_id) {
-  IconMap::iterator it = icon_map_.find(app_id);
+  auto it = icon_map_.find(app_id);
   if (it != icon_map_.end() && it->second.empty())
     icon_map_.erase(it);
 }
diff --git a/chrome/browser/extensions/chrome_app_sorting.cc b/chrome/browser/extensions/chrome_app_sorting.cc
index c44410e..92fde72 100644
--- a/chrome/browser/extensions/chrome_app_sorting.cc
+++ b/chrome/browser/extensions/chrome_app_sorting.cc
@@ -96,8 +96,8 @@
   typedef std::map<syncer::StringOrdinal, std::map<int, const std::string*>,
                    syncer::StringOrdinal::LessThanFn> AppPositionToIdMapping;
   AppPositionToIdMapping app_launches_to_convert;
-  for (extensions::ExtensionIdList::const_iterator ext_id =
-           extension_ids.begin(); ext_id != extension_ids.end(); ++ext_id) {
+  for (auto ext_id = extension_ids.begin(); ext_id != extension_ids.end();
+       ++ext_id) {
     int old_page_index = 0;
     syncer::StringOrdinal page = GetPageOrdinal(*ext_id);
     if (prefs->ReadPrefAsInteger(*ext_id,
@@ -139,10 +139,9 @@
   // Remove any empty pages that may have been added. This shouldn't occur,
   // but double check here to prevent future problems with conversions between
   // integers and StringOrdinals.
-  for (PageOrdinalMap::iterator it = ntp_ordinal_map_.begin();
-       it != ntp_ordinal_map_.end();) {
+  for (auto it = ntp_ordinal_map_.begin(); it != ntp_ordinal_map_.end();) {
     if (it->second.empty()) {
-      PageOrdinalMap::iterator prev_it = it;
+      auto prev_it = it;
       ++it;
       ntp_ordinal_map_.erase(prev_it);
     } else {
@@ -161,9 +160,8 @@
            app_launches_to_convert.begin();
        page_it != app_launches_to_convert.end(); ++page_it) {
     syncer::StringOrdinal page = page_it->first;
-    for (std::map<int, const std::string*>::const_iterator launch_it =
-            page_it->second.begin(); launch_it != page_it->second.end();
-        ++launch_it) {
+    for (auto launch_it = page_it->second.begin();
+         launch_it != page_it->second.end(); ++launch_it) {
       SetAppLaunchOrdinal(*(launch_it->second),
                           CreateNextAppLaunchOrdinal(page));
     }
@@ -171,11 +169,11 @@
 }
 
 void ChromeAppSorting::FixNTPOrdinalCollisions() {
-  for (PageOrdinalMap::iterator page_it = ntp_ordinal_map_.begin();
+  for (auto page_it = ntp_ordinal_map_.begin();
        page_it != ntp_ordinal_map_.end(); ++page_it) {
     AppLaunchOrdinalMap& page = page_it->second;
 
-    AppLaunchOrdinalMap::iterator app_launch_it = page.begin();
+    auto app_launch_it = page.begin();
     while (app_launch_it != page.end()) {
       int app_count = page.count(app_launch_it->first);
       if (app_count == 1) {
@@ -372,8 +370,7 @@
   if (ntp_ordinal_map_.empty())
     return syncer::StringOrdinal::CreateInitialOrdinal();
 
-  for (PageOrdinalMap::const_iterator it = ntp_ordinal_map_.begin();
-       it != ntp_ordinal_map_.end(); ++it) {
+  for (auto it = ntp_ordinal_map_.begin(); it != ntp_ordinal_map_.end(); ++it) {
     if (CountItemsVisibleOnNtp(it->second) < kNaturalAppPageSize)
       return it->first;
   }
@@ -431,7 +428,7 @@
   if (!page_ordinal.IsValid())
     return -1;
 
-  PageOrdinalMap::const_iterator it = ntp_ordinal_map_.find(page_ordinal);
+  auto it = ntp_ordinal_map_.find(page_ordinal);
   return it != ntp_ordinal_map_.end() ?
       std::distance(ntp_ordinal_map_.begin(), it) : -1;
 }
@@ -463,8 +460,7 @@
 
   syncer::StringOrdinal return_value;
 
-  PageOrdinalMap::const_iterator page =
-      ntp_ordinal_map_.find(target_page_ordinal);
+  auto page = ntp_ordinal_map_.find(target_page_ordinal);
   if (page != ntp_ordinal_map_.end()) {
     const AppLaunchOrdinalMap& app_list = page->second;
 
@@ -482,8 +478,8 @@
 
 void ChromeAppSorting::InitializePageOrdinalMap(
     const extensions::ExtensionIdList& extension_ids) {
-  for (extensions::ExtensionIdList::const_iterator ext_it =
-           extension_ids.begin(); ext_it != extension_ids.end(); ++ext_it) {
+  for (auto ext_it = extension_ids.begin(); ext_it != extension_ids.end();
+       ++ext_it) {
     AddOrdinalMapping(*ext_it,
                       GetPageOrdinal(*ext_it),
                       GetAppLaunchOrdinal(*ext_it));
@@ -532,12 +528,11 @@
 
   // Check that the page exists using find to prevent creating a new page
   // if |page_ordinal| isn't a used page.
-  PageOrdinalMap::iterator page_map = ntp_ordinal_map_.find(page_ordinal);
+  auto page_map = ntp_ordinal_map_.find(page_ordinal);
   if (page_map == ntp_ordinal_map_.end())
     return;
 
-  for (AppLaunchOrdinalMap::iterator it =
-           page_map->second.find(app_launch_ordinal);
+  for (auto it = page_map->second.find(app_launch_ordinal);
        it != page_map->second.end(); ++it) {
     if (it->second == extension_id) {
       page_map->second.erase(it);
@@ -602,12 +597,12 @@
     const syncer::StringOrdinal& app_launch_ordinal) const {
   DCHECK(page_ordinal.IsValid() && app_launch_ordinal.IsValid());
 
-  PageOrdinalMap::const_iterator page_it = ntp_ordinal_map_.find(page_ordinal);
+  auto page_it = ntp_ordinal_map_.find(page_ordinal);
   if (page_it == ntp_ordinal_map_.end())
     return app_launch_ordinal;
 
   const AppLaunchOrdinalMap& page = page_it->second;
-  AppLaunchOrdinalMap::const_iterator app_it = page.find(app_launch_ordinal);
+  auto app_it = page.find(app_launch_ordinal);
   if (app_it == page.end())
     return app_launch_ordinal;
 
@@ -629,8 +624,7 @@
 size_t ChromeAppSorting::CountItemsVisibleOnNtp(
     const AppLaunchOrdinalMap& m) const {
   size_t result = 0;
-  for (AppLaunchOrdinalMap::const_iterator it = m.begin(); it != m.end();
-       ++it) {
+  for (auto it = m.begin(); it != m.end(); ++it) {
     const std::string& id = it->second;
     if (ntp_hidden_extensions_.count(id) == 0)
       result++;
diff --git a/chrome/browser/extensions/chrome_app_sorting_unittest.cc b/chrome/browser/extensions/chrome_app_sorting_unittest.cc
index 3cc209a..b60f60c 100644
--- a/chrome/browser/extensions/chrome_app_sorting_unittest.cc
+++ b/chrome/browser/extensions/chrome_app_sorting_unittest.cc
@@ -221,16 +221,14 @@
         app_sorting()->GetPageOrdinal(extensions::kWebStoreAppId);
     EXPECT_TRUE(page.IsValid());
 
-    ChromeAppSorting::PageOrdinalMap::iterator page_it =
-        app_sorting()->ntp_ordinal_map_.find(page);
+    auto page_it = app_sorting()->ntp_ordinal_map_.find(page);
     EXPECT_TRUE(page_it != app_sorting()->ntp_ordinal_map_.end());
 
     syncer::StringOrdinal app_launch =
         app_sorting()->GetPageOrdinal(extensions::kWebStoreAppId);
     EXPECT_TRUE(app_launch.IsValid());
 
-    ChromeAppSorting::AppLaunchOrdinalMap::iterator app_launch_it =
-        page_it->second.find(app_launch);
+    auto app_launch_it = page_it->second.find(app_launch);
     EXPECT_TRUE(app_launch_it != page_it->second.end());
   }
 };
@@ -549,7 +547,7 @@
     EXPECT_EQ(1U, app_sorting()->ntp_ordinal_map_.size());
     EXPECT_EQ(2U, app_sorting()->ntp_ordinal_map_[first_ordinal].size());
 
-    ChromeAppSorting::AppLaunchOrdinalMap::iterator it =
+    auto it =
         app_sorting()->ntp_ordinal_map_[first_ordinal].find(first_ordinal);
     EXPECT_EQ(ext_1, it->second);
     ++it;
diff --git a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
index 5a4b6cf..073089c 100644
--- a/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
+++ b/chrome/browser/extensions/chrome_component_extension_resource_manager.cc
@@ -89,8 +89,7 @@
   relative_path = relative_path.Append(resource_path);
   relative_path = relative_path.NormalizePathSeparators();
 
-  std::map<base::FilePath, int>::const_iterator entry =
-      path_to_resource_id_.find(relative_path);
+  auto entry = path_to_resource_id_.find(relative_path);
   if (entry != path_to_resource_id_.end())
     *resource_id = entry->second;
 
diff --git a/chrome/browser/extensions/component_loader.cc b/chrome/browser/extensions/component_loader.cc
index ebbb3faa..e54620b 100644
--- a/chrome/browser/extensions/component_loader.cc
+++ b/chrome/browser/extensions/component_loader.cc
@@ -271,8 +271,7 @@
 }
 
 void ComponentLoader::Remove(const std::string& id) {
-  for (RegisteredComponentExtensions::iterator it =
-           component_extensions_.begin();
+  for (auto it = component_extensions_.begin();
        it != component_extensions_.end(); ++it) {
     if (it->extension_id == id) {
       UnloadComponent(&(*it));
diff --git a/chrome/browser/extensions/context_menu_matcher.cc b/chrome/browser/extensions/context_menu_matcher.cc
index fc51177e..80122d20 100644
--- a/chrome/browser/extensions/context_menu_matcher.cc
+++ b/chrome/browser/extensions/context_menu_matcher.cc
@@ -337,8 +337,7 @@
 
 MenuItem* ContextMenuMatcher::GetExtensionMenuItem(int id) const {
   MenuManager* manager = MenuManager::Get(browser_context_);
-  std::map<int, MenuItem::Id>::const_iterator i =
-      extension_item_map_.find(id);
+  auto i = extension_item_map_.find(id);
   if (i != extension_item_map_.end()) {
     MenuItem* item = manager->GetItemById(i->second);
     if (item)
diff --git a/chrome/browser/extensions/convert_user_script.cc b/chrome/browser/extensions/convert_user_script.cc
index 66ddb10..80e4551b 100644
--- a/chrome/browser/extensions/convert_user_script.cc
+++ b/chrome/browser/extensions/convert_user_script.cc
@@ -109,7 +109,7 @@
   // generate some using the include globs.
   auto matches = std::make_unique<base::ListValue>();
   if (!script.url_patterns().is_empty()) {
-    for (URLPatternSet::const_iterator i = script.url_patterns().begin();
+    for (auto i = script.url_patterns().begin();
          i != script.url_patterns().end(); ++i) {
       matches->AppendString(i->GetAsString());
     }
@@ -122,8 +122,7 @@
   // Read the exclude matches, if any are present.
   auto exclude_matches = std::make_unique<base::ListValue>();
   if (!script.exclude_url_patterns().is_empty()) {
-    for (URLPatternSet::const_iterator i =
-         script.exclude_url_patterns().begin();
+    for (auto i = script.exclude_url_patterns().begin();
          i != script.exclude_url_patterns().end(); ++i) {
       exclude_matches->AppendString(i->GetAsString());
     }
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index 3d8ce3f..a306b459 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -455,8 +455,7 @@
       pattern.SetMatchSubdomains(true);
 
       const URLPatternSet& patterns = extension_->web_extent();
-      for (URLPatternSet::const_iterator i = patterns.begin();
-           i != patterns.end(); ++i) {
+      for (auto i = patterns.begin(); i != patterns.end(); ++i) {
         if (!pattern.MatchesHost(i->host())) {
           return CrxInstallError(
               CrxInstallErrorType::OTHER,
diff --git a/chrome/browser/extensions/default_apps.cc b/chrome/browser/extensions/default_apps.cc
index aafdde0..0c3a25a 100644
--- a/chrome/browser/extensions/default_apps.cc
+++ b/chrome/browser/extensions/default_apps.cc
@@ -156,8 +156,8 @@
         new_default_apps.insert(i.key());
     }
     // Filter out the new default apps for migrating users.
-    for (std::set<std::string>::iterator it = new_default_apps.begin();
-         it != new_default_apps.end(); ++it) {
+    for (auto it = new_default_apps.begin(); it != new_default_apps.end();
+         ++it) {
       prefs->Remove(*it, NULL);
     }
   }
diff --git a/chrome/browser/extensions/error_console/error_console.cc b/chrome/browser/extensions/error_console/error_console.cc
index c5bae28..f0560e2a 100644
--- a/chrome/browser/extensions/error_console/error_console.cc
+++ b/chrome/browser/extensions/error_console/error_console.cc
@@ -259,8 +259,7 @@
 void ErrorConsole::AddManifestErrorsForExtension(const Extension* extension) {
   const std::vector<InstallWarning>& warnings =
       extension->install_warnings();
-  for (std::vector<InstallWarning>::const_iterator iter = warnings.begin();
-       iter != warnings.end(); ++iter) {
+  for (auto iter = warnings.begin(); iter != warnings.end(); ++iter) {
     ReportError(std::unique_ptr<ExtensionError>(new ManifestError(
         extension->id(), base::UTF8ToUTF16(iter->message),
         base::UTF8ToUTF16(iter->key), base::UTF8ToUTF16(iter->specific))));
diff --git a/chrome/browser/extensions/extension_action.cc b/chrome/browser/extensions/extension_action.cc
index 4c05554..749ba6a 100644
--- a/chrome/browser/extensions/extension_action.cc
+++ b/chrome/browser/extensions/extension_action.cc
@@ -195,8 +195,7 @@
                                              int priority,
                                              const gfx::Image& icon) {
   std::vector<gfx::Image>& icons = declarative_icon_[tab_id][priority];
-  for (std::vector<gfx::Image>::iterator it = icons.begin(); it != icons.end();
-       ++it) {
+  for (auto it = icons.begin(); it != icons.end(); ++it) {
     if (it->AsImageSkia().BackedBySameObjectAs(icon.AsImageSkia())) {
       icons.erase(it);
       return;
diff --git a/chrome/browser/extensions/extension_action_runner.cc b/chrome/browser/extensions/extension_action_runner.cc
index e66a5c69..f27f5078 100644
--- a/chrome/browser/extensions/extension_action_runner.cc
+++ b/chrome/browser/extensions/extension_action_runner.cc
@@ -272,7 +272,7 @@
   // callbacks adds more entries.
   permitted_extensions_.insert(extension->id());
 
-  PendingScriptMap::iterator iter = pending_scripts_.find(extension->id());
+  auto iter = pending_scripts_.find(extension->id());
   if (iter == pending_scripts_.end())
     return;
 
@@ -530,7 +530,7 @@
     content::BrowserContext* browser_context,
     const Extension* extension,
     UnloadedExtensionReason reason) {
-  PendingScriptMap::iterator iter = pending_scripts_.find(extension->id());
+  auto iter = pending_scripts_.find(extension->id());
   if (iter != pending_scripts_.end()) {
     pending_scripts_.erase(iter);
     ExtensionActionAPI::Get(browser_context_)
diff --git a/chrome/browser/extensions/extension_action_runner_unittest.cc b/chrome/browser/extensions/extension_action_runner_unittest.cc
index 06a0f2f9..647784792 100644
--- a/chrome/browser/extensions/extension_action_runner_unittest.cc
+++ b/chrome/browser/extensions/extension_action_runner_unittest.cc
@@ -152,8 +152,7 @@
 
 size_t ExtensionActionRunnerUnitTest::GetExecutionCountForExtension(
     const std::string& extension_id) const {
-  std::map<std::string, int>::const_iterator iter =
-      extension_executions_.find(extension_id);
+  auto iter = extension_executions_.find(extension_id);
   if (iter != extension_executions_.end())
     return iter->second;
   return 0u;
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 2d90540c..79816a1b 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -496,8 +496,7 @@
     VLOG(1) << "Errors follow:";
     const std::vector<base::string16>* errors =
         LoadErrorReporter::GetInstance()->GetErrors();
-    for (std::vector<base::string16>::const_iterator iter = errors->begin();
-         iter != errors->end(); ++iter)
+    for (auto iter = errors->begin(); iter != errors->end(); ++iter)
       VLOG(1) << *iter;
 
     return NULL;
diff --git a/chrome/browser/extensions/extension_commands_global_registry_apitest.cc b/chrome/browser/extensions/extension_commands_global_registry_apitest.cc
index 1ce7121..6f5d85b6 100644
--- a/chrome/browser/extensions/extension_commands_global_registry_apitest.cc
+++ b/chrome/browser/extensions/extension_commands_global_registry_apitest.cc
@@ -62,11 +62,11 @@
                                        XKeysymForWindowsKeyCode(key, false)));
 
   // Simulate the keys being pressed.
-  for (KeyCodes::iterator it = key_codes.begin(); it != key_codes.end(); it++)
+  for (auto it = key_codes.begin(); it != key_codes.end(); it++)
     XTestFakeKeyEvent(display, *it, x11::True, x11::CurrentTime);
 
   // Simulate the keys being released.
-  for (KeyCodes::iterator it = key_codes.begin(); it != key_codes.end(); it++)
+  for (auto it = key_codes.begin(); it != key_codes.end(); it++)
     XTestFakeKeyEvent(display, *it, x11::False, x11::CurrentTime);
 
   XFlush(display);
diff --git a/chrome/browser/extensions/extension_garbage_collector.cc b/chrome/browser/extensions/extension_garbage_collector.cc
index 3ff2f91..10f1ce42 100644
--- a/chrome/browser/extensions/extension_garbage_collector.cc
+++ b/chrome/browser/extensions/extension_garbage_collector.cc
@@ -95,7 +95,7 @@
        !version_dir.empty();
        version_dir = versions_enumerator.Next()) {
     bool known_version = false;
-    for (Iter iter = iter_pair.first; iter != iter_pair.second; ++iter) {
+    for (auto iter = iter_pair.first; iter != iter_pair.second; ++iter) {
       if (version_dir.BaseName() == iter->second.BaseName()) {
         known_version = true;
         break;
diff --git a/chrome/browser/extensions/extension_keybinding_registry.cc b/chrome/browser/extensions/extension_keybinding_registry.cc
index fbd9075f..9957a20 100644
--- a/chrome/browser/extensions/extension_keybinding_registry.cc
+++ b/chrome/browser/extensions/extension_keybinding_registry.cc
@@ -57,10 +57,10 @@
 void ExtensionKeybindingRegistry::RemoveExtensionKeybinding(
     const Extension* extension,
     const std::string& command_name) {
-  EventTargets::iterator it = event_targets_.begin();
+  auto it = event_targets_.begin();
   while (it != event_targets_.end()) {
     TargetList& target_list = it->second;
-    TargetList::iterator target = target_list.begin();
+    auto target = target_list.begin();
     while (target != target_list.end()) {
       if (target->first == extension->id() &&
           (command_name.empty() || command_name == target->second))
@@ -69,7 +69,7 @@
         target++;
     }
 
-    EventTargets::iterator old = it++;
+    auto old = it++;
     if (target_list.empty()) {
       // Let each platform-specific implementation get a chance to clean up.
       RemoveExtensionKeybindingImpl(old->first, command_name);
@@ -167,12 +167,12 @@
     const ui::Accelerator& accelerator,
     std::string* extension_id,
     std::string* command_name) const {
-  EventTargets::const_iterator targets = event_targets_.find(accelerator);
+  auto targets = event_targets_.find(accelerator);
   if (targets == event_targets_.end())
     return false;
 
   DCHECK(!targets->second.empty());
-  TargetList::const_iterator first_target = targets->second.begin();
+  auto first_target = targets->second.begin();
   *extension_id = first_target->first;
   *command_name = first_target->second;
   return true;
@@ -268,7 +268,7 @@
 bool ExtensionKeybindingRegistry::ExecuteCommands(
     const ui::Accelerator& accelerator,
     const std::string& extension_id) {
-  EventTargets::iterator targets = event_targets_.find(accelerator);
+  auto targets = event_targets_.find(accelerator);
   if (targets == event_targets_.end() || targets->second.empty())
     return false;
 
diff --git a/chrome/browser/extensions/extension_management.cc b/chrome/browser/extensions/extension_management.cc
index b482885f..313ce22 100644
--- a/chrome/browser/extensions/extension_management.cc
+++ b/chrome/browser/extensions/extension_management.cc
@@ -340,16 +340,16 @@
   ExtensionId id;
 
   if (allowed_list_pref) {
-    for (base::ListValue::const_iterator it = allowed_list_pref->begin();
-         it != allowed_list_pref->end(); ++it) {
+    for (auto it = allowed_list_pref->begin(); it != allowed_list_pref->end();
+         ++it) {
       if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
         AccessById(id)->installation_mode = INSTALLATION_ALLOWED;
     }
   }
 
   if (denied_list_pref) {
-    for (base::ListValue::const_iterator it = denied_list_pref->begin();
-         it != denied_list_pref->end(); ++it) {
+    for (auto it = denied_list_pref->begin(); it != denied_list_pref->end();
+         ++it) {
       if (it->GetAsString(&id) && crx_file::id_util::IdIsValid(id))
         AccessById(id)->installation_mode = INSTALLATION_BLOCKED;
     }
@@ -360,7 +360,7 @@
 
   if (install_sources_pref) {
     global_settings_->has_restricted_install_sources = true;
-    for (base::ListValue::const_iterator it = install_sources_pref->begin();
+    for (auto it = install_sources_pref->begin();
          it != install_sources_pref->end(); ++it) {
       std::string url_pattern;
       if (it->GetAsString(&url_pattern)) {
@@ -378,8 +378,8 @@
 
   if (allowed_types_pref) {
     global_settings_->has_restricted_allowed_types = true;
-    for (base::ListValue::const_iterator it = allowed_types_pref->begin();
-         it != allowed_types_pref->end(); ++it) {
+    for (auto it = allowed_types_pref->begin(); it != allowed_types_pref->end();
+         ++it) {
       int int_value;
       std::string string_value;
       if (it->GetAsInteger(&int_value) && int_value >= 0 &&
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 90397a3..70739ee 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -1804,9 +1804,7 @@
         // extensions could be referencing a shared module which is waiting for
         // idle to update.  Check all imports of these extensions, too.
         std::set<std::string> import_ids;
-        for (std::set<std::string>::const_iterator it = extension_ids.begin();
-             it != extension_ids.end();
-             ++it) {
+        for (auto it = extension_ids.begin(); it != extension_ids.end(); ++it) {
           const Extension* extension = GetExtensionById(*it, true);
           if (!extension)
             continue;
@@ -1820,8 +1818,7 @@
         }
         extension_ids.insert(import_ids.begin(), import_ids.end());
 
-        for (std::set<std::string>::const_iterator it = extension_ids.begin();
-             it != extension_ids.end(); ++it) {
+        for (auto it = extension_ids.begin(); it != extension_ids.end(); ++it) {
           if (delayed_installs_.Contains(*it)) {
             base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
                 FROM_HERE,
@@ -2051,8 +2048,8 @@
   Partition(registry_->blacklisted_extensions().GetIDs(), blacklisted,
             unchanged, &no_longer_blocked, &not_yet_blocked);
 
-  for (ExtensionIdSet::iterator it = no_longer_blocked.begin();
-       it != no_longer_blocked.end(); ++it) {
+  for (auto it = no_longer_blocked.begin(); it != no_longer_blocked.end();
+       ++it) {
     scoped_refptr<const Extension> extension =
         registry_->blacklisted_extensions().GetByID(*it);
     if (!extension.get()) {
@@ -2069,8 +2066,7 @@
                               Manifest::NUM_LOCATIONS);
   }
 
-  for (ExtensionIdSet::iterator it = not_yet_blocked.begin();
-       it != not_yet_blocked.end(); ++it) {
+  for (auto it = not_yet_blocked.begin(); it != not_yet_blocked.end(); ++it) {
     scoped_refptr<const Extension> extension = GetInstalledExtension(*it);
     if (!extension.get()) {
       NOTREACHED() << "Extension " << *it << " needs to be "
@@ -2096,8 +2092,8 @@
             greylist, unchanged,
             &no_longer_greylisted, &not_yet_greylisted);
 
-  for (ExtensionIdSet::iterator it = no_longer_greylisted.begin();
-       it != no_longer_greylisted.end(); ++it) {
+  for (auto it = no_longer_greylisted.begin(); it != no_longer_greylisted.end();
+       ++it) {
     scoped_refptr<const Extension> extension = greylist_.GetByID(*it);
     if (!extension.get()) {
       NOTREACHED() << "Extension " << *it << " no longer greylisted, "
@@ -2113,8 +2109,8 @@
       EnableExtension(*it);
   }
 
-  for (ExtensionIdSet::iterator it = not_yet_greylisted.begin();
-       it != not_yet_greylisted.end(); ++it) {
+  for (auto it = not_yet_greylisted.begin(); it != not_yet_greylisted.end();
+       ++it) {
     scoped_refptr<const Extension> extension = GetInstalledExtension(*it);
     if (!extension.get()) {
       NOTREACHED() << "Extension " << *it << " needs to be "
@@ -2168,9 +2164,7 @@
 
 void ExtensionService::OnProfileDestructionStarted() {
   ExtensionIdSet ids_to_unload = registry_->enabled_extensions().GetIDs();
-  for (ExtensionIdSet::iterator it = ids_to_unload.begin();
-       it != ids_to_unload.end();
-       ++it) {
+  for (auto it = ids_to_unload.begin(); it != ids_to_unload.end(); ++it) {
     UnloadExtension(*it, UnloadedExtensionReason::PROFILE_SHUTDOWN);
   }
 }
diff --git a/chrome/browser/extensions/extension_service_test_with_install.cc b/chrome/browser/extensions/extension_service_test_with_install.cc
index 3c2d8bc..463488d5 100644
--- a/chrome/browser/extensions/extension_service_test_with_install.cc
+++ b/chrome/browser/extensions/extension_service_test_with_install.cc
@@ -228,8 +228,7 @@
           << path.value();
     }
 
-    for (std::vector<base::string16>::iterator err = errors.begin();
-      err != errors.end(); ++err) {
+    for (auto err = errors.begin(); err != errors.end(); ++err) {
       LOG(ERROR) << *err;
     }
   } else {
@@ -374,13 +373,12 @@
     UnloadedExtensionReason reason) {
   unloaded_id_ = extension->id();
   unloaded_reason_ = reason;
-  extensions::ExtensionList::iterator i =
-      std::find(loaded_.begin(), loaded_.end(), extension);
-      // TODO(erikkay) fix so this can be an assert.  Right now the tests
-      // are manually calling clear() on loaded_, so this isn't doable.
-      if (i == loaded_.end())
-        return;
-      loaded_.erase(i);
+  auto i = std::find(loaded_.begin(), loaded_.end(), extension);
+  // TODO(erikkay) fix so this can be an assert.  Right now the tests
+  // are manually calling clear() on loaded_, so this isn't doable.
+  if (i == loaded_.end())
+    return;
+  loaded_.erase(i);
 }
 
 void ExtensionServiceTestWithInstall::OnExtensionWillBeInstalled(
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 73308a7..444f1c7 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -732,8 +732,7 @@
     msg += extension_id + " " + pref_path;
 
     auto list_value = std::make_unique<base::ListValue>();
-    for (std::set<std::string>::const_iterator iter = value.begin();
-         iter != value.end(); ++iter)
+    for (auto iter = value.begin(); iter != value.end(); ++iter)
       list_value->AppendString(*iter);
 
     SetPref(extension_id, pref_path, std::move(list_value), msg);
diff --git a/chrome/browser/extensions/extension_storage_monitor.cc b/chrome/browser/extensions/extension_storage_monitor.cc
index 4015427..b1000628 100644
--- a/chrome/browser/extensions/extension_storage_monitor.cc
+++ b/chrome/browser/extensions/extension_storage_monitor.cc
@@ -532,8 +532,7 @@
 
 void ExtensionStorageMonitor::RemoveNotificationForExtension(
     const std::string& extension_id) {
-  std::set<std::string>::iterator ext_id =
-      notified_extension_ids_.find(extension_id);
+  auto ext_id = notified_extension_ids_.find(extension_id);
   if (ext_id == notified_extension_ids_.end())
     return;
 
diff --git a/chrome/browser/extensions/extension_web_ui.cc b/chrome/browser/extensions/extension_web_ui.cc
index 48520165..f112961 100644
--- a/chrome/browser/extensions/extension_web_ui.cc
+++ b/chrome/browser/extensions/extension_web_ui.cc
@@ -193,7 +193,7 @@
 bool UpdateOverridesList(base::ListValue* overrides_list,
                          const std::string& override_url,
                          UpdateBehavior behavior) {
-  base::ListValue::iterator iter = std::find_if(
+  auto iter = std::find_if(
       overrides_list->begin(), overrides_list->end(),
       [&override_url](const base::Value& value) {
         std::string entry;
@@ -440,8 +440,8 @@
     if (!dict_iter.value().GetAsList(&url_list))
       continue;
 
-    for (base::ListValue::const_iterator list_iter = url_list->begin();
-         list_iter != url_list->end(); ++list_iter) {
+    for (auto list_iter = url_list->begin(); list_iter != url_list->end();
+         ++list_iter) {
       const base::DictionaryValue* dict = nullptr;
       if (!list_iter->GetAsDictionary(&dict))
         continue;
diff --git a/chrome/browser/extensions/external_pref_loader.cc b/chrome/browser/extensions/external_pref_loader.cc
index fb50262..69d3c70 100644
--- a/chrome/browser/extensions/external_pref_loader.cc
+++ b/chrome/browser/extensions/external_pref_loader.cc
@@ -324,9 +324,7 @@
 
   // For each file read the json description & build the proper
   // associated prefs.
-  for (std::set<base::FilePath>::const_iterator it = candidates.begin();
-       it != candidates.end();
-       ++it) {
+  for (auto it = candidates.begin(); it != candidates.end(); ++it) {
     base::FilePath extension_candidate_path = base_path_.Append(*it);
 
     std::string id =
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc
index 0fe8e8ea..4da1e63c 100644
--- a/chrome/browser/extensions/external_provider_impl.cc
+++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -409,7 +409,7 @@
     }
   }
 
-  for (std::set<std::string>::iterator it = unsupported_extensions.begin();
+  for (auto it = unsupported_extensions.begin();
        it != unsupported_extensions.end(); ++it) {
     // Remove extension for the list of know external extensions. The extension
     // will be uninstalled later because provider doesn't provide it anymore.
diff --git a/chrome/browser/extensions/global_shortcut_listener.cc b/chrome/browser/extensions/global_shortcut_listener.cc
index 925cb40d..937b54c 100644
--- a/chrome/browser/extensions/global_shortcut_listener.cc
+++ b/chrome/browser/extensions/global_shortcut_listener.cc
@@ -53,7 +53,7 @@
   if (IsShortcutHandlingSuspended())
     return;
 
-  AcceleratorMap::iterator it = accelerator_map_.find(accelerator);
+  auto it = accelerator_map_.find(accelerator);
   // We should never get asked to unregister something that we didn't register.
   DCHECK(it != accelerator_map_.end());
   // The caller should call this function with the right observer.
@@ -70,10 +70,10 @@
   if (IsShortcutHandlingSuspended())
     return;
 
-  AcceleratorMap::iterator it = accelerator_map_.begin();
+  auto it = accelerator_map_.begin();
   while (it != accelerator_map_.end()) {
     if (it->second == observer) {
-      AcceleratorMap::iterator to_remove = it++;
+      auto to_remove = it++;
       UnregisterAccelerator(to_remove->first, observer);
     } else {
       ++it;
@@ -87,9 +87,7 @@
     return;
 
   shortcut_handling_suspended_ = suspended;
-  for (AcceleratorMap::iterator it = accelerator_map_.begin();
-       it != accelerator_map_.end();
-       ++it) {
+  for (auto it = accelerator_map_.begin(); it != accelerator_map_.end(); ++it) {
     // On Linux, when shortcut handling is suspended we cannot simply early
     // return in NotifyKeyPressed (similar to what we do for non-global
     // shortcuts) because we'd eat the keyboard event thereby preventing the
@@ -108,7 +106,7 @@
 
 void GlobalShortcutListener::NotifyKeyPressed(
     const ui::Accelerator& accelerator) {
-  AcceleratorMap::iterator iter = accelerator_map_.find(accelerator);
+  auto iter = accelerator_map_.find(accelerator);
   if (iter == accelerator_map_.end()) {
     // This should never occur, because if it does, we have failed to unregister
     // or failed to clean up the map after unregistering the shortcut.
diff --git a/chrome/browser/extensions/install_signer.cc b/chrome/browser/extensions/install_signer.cc
index 15fb04ad..6341caf 100644
--- a/chrome/browser/extensions/install_signer.cc
+++ b/chrome/browser/extensions/install_signer.cc
@@ -127,7 +127,7 @@
                        const char* key,
                        const ExtensionIdSet& ids) {
   auto id_list = std::make_unique<base::ListValue>();
-  for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i)
+  for (auto i = ids.begin(); i != ids.end(); ++i)
     id_list->AppendString(*i);
   dictionary->Set(key, std::move(id_list));
 }
@@ -142,9 +142,7 @@
   const base::ListValue* id_list = NULL;
   if (!dictionary.GetList(key, &id_list))
     return false;
-  for (base::ListValue::const_iterator i = id_list->begin();
-       i != id_list->end();
-       ++i) {
+  for (auto i = id_list->begin(); i != id_list->end(); ++i) {
     std::string id;
     if (!i->GetAsString(&id)) {
       return false;
@@ -242,8 +240,7 @@
     return true;
 
   std::string signed_data;
-  for (ExtensionIdSet::const_iterator i = signature.ids.begin();
-       i != signature.ids.end(); ++i)
+  for (auto i = signature.ids.begin(); i != signature.ids.end(); ++i)
     signed_data.append(*i);
 
   std::string hash_base64;
@@ -388,7 +385,7 @@
   dictionary.SetInteger(kProtocolVersionKey, 1);
   dictionary.SetString(kHashKey, hash_base64);
   std::unique_ptr<base::ListValue> id_list(new base::ListValue);
-  for (ExtensionIdSet::const_iterator i = ids_.begin(); i != ids_.end(); ++i) {
+  for (auto i = ids_.begin(); i != ids_.end(); ++i) {
     id_list->AppendString(*i);
   }
   dictionary.Set(kIdsKey, std::move(id_list));
diff --git a/chrome/browser/extensions/install_tracker.cc b/chrome/browser/extensions/install_tracker.cc
index bda36cf..fbffefc3 100644
--- a/chrome/browser/extensions/install_tracker.cc
+++ b/chrome/browser/extensions/install_tracker.cc
@@ -54,8 +54,7 @@
 
 const ActiveInstallData* InstallTracker::GetActiveInstall(
     const std::string& extension_id) const {
-  ActiveInstallsMap::const_iterator install_data =
-      active_installs_.find(extension_id);
+  auto install_data = active_installs_.find(extension_id);
   if (install_data == active_installs_.end())
     return NULL;
   else
@@ -76,8 +75,7 @@
 
 void InstallTracker::OnBeginExtensionInstall(
     const InstallObserver::ExtensionInstallParams& params) {
-  ActiveInstallsMap::iterator install_data =
-      active_installs_.find(params.extension_id);
+  auto install_data = active_installs_.find(params.extension_id);
   if (install_data == active_installs_.end()) {
     ActiveInstallData install_data(params.extension_id);
     active_installs_.insert(std::make_pair(params.extension_id, install_data));
@@ -94,8 +92,7 @@
 
 void InstallTracker::OnDownloadProgress(const std::string& extension_id,
                                         int percent_downloaded) {
-  ActiveInstallsMap::iterator install_data =
-      active_installs_.find(extension_id);
+  auto install_data = active_installs_.find(extension_id);
   if (install_data != active_installs_.end()) {
     install_data->second.percent_downloaded = percent_downloaded;
   } else {
diff --git a/chrome/browser/extensions/install_verifier.cc b/chrome/browser/extensions/install_verifier.cc
index ed1d3ad..8fd766c 100644
--- a/chrome/browser/extensions/install_verifier.cc
+++ b/chrome/browser/extensions/install_verifier.cc
@@ -319,7 +319,7 @@
     return;
 
   bool found_any = false;
-  for (ExtensionIdSet::const_iterator i = ids.begin(); i != ids.end(); ++i) {
+  for (auto i = ids.begin(); i != ids.end(); ++i) {
     if (base::ContainsKey(signature_->ids, *i) ||
         base::ContainsKey(signature_->invalid_ids, *i)) {
       found_any = true;
@@ -477,8 +477,7 @@
   if (signature_.get() == NULL && ShouldFetchSignature()) {
     needs_bootstrap = true;
   } else {
-    for (ExtensionIdSet::const_iterator iter = extension_ids.begin();
-         iter != extension_ids.end();
+    for (auto iter = extension_ids.begin(); iter != extension_ids.end();
          ++iter) {
       if (!IsKnownId(*iter)) {
         needs_bootstrap = true;
@@ -544,7 +543,7 @@
   prefs_->GetExtensions(&all_ids);
   for (ExtensionIdList::const_iterator i = all_ids.begin();
        i != all_ids.end(); ++i) {
-    ExtensionIdSet::iterator found = leftovers.find(*i);
+    auto found = leftovers.find(*i);
     if (found != leftovers.end())
       leftovers.erase(found);
   }
@@ -572,8 +571,7 @@
     ids_to_sign.insert(signature_->ids.begin(), signature_->ids.end());
   }
   if (operation.type == InstallVerifier::REMOVE) {
-    for (ExtensionIdSet::const_iterator i = operation.ids.begin();
-         i != operation.ids.end(); ++i) {
+    for (auto i = operation.ids.begin(); i != operation.ids.end(); ++i) {
       if (base::ContainsKey(ids_to_sign, *i))
         ids_to_sign.erase(*i);
     }
diff --git a/chrome/browser/extensions/isolated_app_browsertest.cc b/chrome/browser/extensions/isolated_app_browsertest.cc
index 152c88f..d85e9d6 100644
--- a/chrome/browser/extensions/isolated_app_browsertest.cc
+++ b/chrome/browser/extensions/isolated_app_browsertest.cc
@@ -126,8 +126,8 @@
         ProcessMap::Get(browser_context)
             ->GetExtensionsInProcess(
                 contents->GetMainFrame()->GetProcess()->GetID());
-    for (std::set<std::string>::iterator iter = extension_ids.begin();
-         iter != extension_ids.end(); ++iter) {
+    for (auto iter = extension_ids.begin(); iter != extension_ids.end();
+         ++iter) {
       const Extension* installed_app =
           registry->enabled_extensions().GetByID(*iter);
       if (installed_app && installed_app->is_app())
diff --git a/chrome/browser/extensions/menu_manager.cc b/chrome/browser/extensions/menu_manager.cc
index 2fc379b..e8d2c1b 100644
--- a/chrome/browser/extensions/menu_manager.cc
+++ b/chrome/browser/extensions/menu_manager.cc
@@ -768,7 +768,7 @@
     // Uncheck any checked radio items in the run, and at the end reset
     // the appropriate one to checked. If no check radio items were found,
     // then check the first radio item in the run.
-    MenuItem::OwnedList::const_iterator last_checked = item_list.end();
+    auto last_checked = item_list.end();
     MenuItem::OwnedList::const_iterator radio_run_iter;
     for (radio_run_iter = i; radio_run_iter != item_list.end();
         ++radio_run_iter) {
diff --git a/chrome/browser/extensions/plugin_manager.cc b/chrome/browser/extensions/plugin_manager.cc
index 48294801..962415f4 100644
--- a/chrome/browser/extensions/plugin_manager.cc
+++ b/chrome/browser/extensions/plugin_manager.cc
@@ -54,8 +54,7 @@
       NaClModuleInfo::GetNaClModules(extension);
   if (nacl_modules) {
     plugins_or_nacl_changed = true;
-    for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
-         module != nacl_modules->end();
+    for (auto module = nacl_modules->begin(); module != nacl_modules->end();
          ++module) {
       RegisterNaClModule(*module);
     }
@@ -73,8 +72,7 @@
     info.path = handler->GetPluginPath();
     info.background_color = handler->GetBackgroundColor();
 
-    for (std::set<std::string>::const_iterator mime_type =
-         handler->mime_type_set().begin();
+    for (auto mime_type = handler->mime_type_set().begin();
          mime_type != handler->mime_type_set().end(); ++mime_type) {
       content::WebPluginMimeType mime_type_info;
       mime_type_info.mime_type = *mime_type;
@@ -104,8 +102,7 @@
       NaClModuleInfo::GetNaClModules(extension);
   if (nacl_modules) {
     plugins_or_nacl_changed = true;
-    for (NaClModuleInfo::List::const_iterator module = nacl_modules->begin();
-         module != nacl_modules->end();
+    for (auto module = nacl_modules->begin(); module != nacl_modules->end();
          ++module) {
       UnregisterNaClModule(*module);
     }
@@ -133,7 +130,7 @@
 }
 
 void PluginManager::UnregisterNaClModule(const NaClModuleInfo& info) {
-  NaClModuleInfo::List::iterator iter = FindNaClModule(info.url);
+  auto iter = FindNaClModule(info.url);
   DCHECK(iter != nacl_module_list_.end());
   nacl_module_list_.erase(iter);
 }
@@ -183,8 +180,8 @@
 }
 
 NaClModuleInfo::List::iterator PluginManager::FindNaClModule(const GURL& url) {
-  for (NaClModuleInfo::List::iterator iter = nacl_module_list_.begin();
-       iter != nacl_module_list_.end(); ++iter) {
+  for (auto iter = nacl_module_list_.begin(); iter != nacl_module_list_.end();
+       ++iter) {
     if (iter->url == url)
       return iter;
   }
diff --git a/chrome/browser/extensions/policy_handlers.cc b/chrome/browser/extensions/policy_handlers.cc
index bf33b5d..fc63cc0 100644
--- a/chrome/browser/extensions/policy_handlers.cc
+++ b/chrome/browser/extensions/policy_handlers.cc
@@ -96,7 +96,7 @@
     return false;
   }
 
-  for (base::ListValue::const_iterator entry(policy_list_value->begin());
+  for (auto entry(policy_list_value->begin());
        entry != policy_list_value->end(); ++entry) {
     std::string entry_string;
     if (!entry->GetAsString(&entry_string)) {
@@ -183,8 +183,7 @@
   }
 
   // Check that the list contains valid URLPattern strings only.
-  for (base::ListValue::const_iterator entry(list_value->begin());
-       entry != list_value->end(); ++entry) {
+  for (auto entry(list_value->begin()); entry != list_value->end(); ++entry) {
     std::string url_pattern_string;
     if (!entry->GetAsString(&url_pattern_string)) {
       errors->AddError(policy_name(), entry - list_value->begin(),
diff --git a/chrome/browser/extensions/shared_module_service.cc b/chrome/browser/extensions/shared_module_service.cc
index a3f0f70..53b826a6 100644
--- a/chrome/browser/extensions/shared_module_service.cc
+++ b/chrome/browser/extensions/shared_module_service.cc
@@ -50,9 +50,7 @@
   // at install time, those locations need to be updated.
   ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
   const ImportInfoVector& imports = SharedModuleInfo::GetImports(extension);
-  for (ImportInfoVector::const_iterator iter = imports.begin();
-       iter != imports.end();
-       ++iter) {
+  for (auto iter = imports.begin(); iter != imports.end(); ++iter) {
     base::Version version_required(iter->minimum_version);
     const Extension* imported_module =
         registry->GetExtensionById(iter->extension_id,
@@ -170,8 +168,7 @@
       shared_modules.push_back(iter->get()->id());
 
     const ImportInfoVector& imports = SharedModuleInfo::GetImports(iter->get());
-    for (ImportInfoVector::const_iterator imports_iter = imports.begin();
-         imports_iter != imports.end();
+    for (auto imports_iter = imports.begin(); imports_iter != imports.end();
          ++imports_iter) {
       used_shared_modules.insert(imports_iter->extension_id);
     }
diff --git a/chrome/browser/extensions/startup_helper_browsertest.cc b/chrome/browser/extensions/startup_helper_browsertest.cc
index b8855bd..eade729 100644
--- a/chrome/browser/extensions/startup_helper_browsertest.cc
+++ b/chrome/browser/extensions/startup_helper_browsertest.cc
@@ -46,9 +46,7 @@
   expectations.push_back(
       std::make_pair(test_data_dir_.AppendASCII("bad_magic.crx"), false));
 
-  for (std::vector<std::pair<base::FilePath, bool> >::iterator i =
-           expectations.begin();
-       i != expectations.end(); ++i) {
+  for (auto i = expectations.begin(); i != expectations.end(); ++i) {
     base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
     const base::FilePath& path = i->first;
     command_line.AppendSwitchPath(switches::kValidateCrx, path);
diff --git a/chrome/browser/extensions/updater/extension_cache_fake.cc b/chrome/browser/extensions/updater/extension_cache_fake.cc
index 984c5c2d..5774ecf9 100644
--- a/chrome/browser/extensions/updater/extension_cache_fake.cc
+++ b/chrome/browser/extensions/updater/extension_cache_fake.cc
@@ -34,7 +34,7 @@
                                       const std::string& expected_hash,
                                       base::FilePath* file_path,
                                       std::string* version) {
-  Map::iterator it = cache_.find(id);
+  auto it = cache_.find(id);
   if (it == cache_.end()) {
     return false;
   } else {
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index bc9cb564..9a3393baa 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -647,8 +647,7 @@
   std::map<std::string, std::string> expected;
   ExtractParameters(omaha_params, &expected);
 
-  for (std::map<std::string, std::string>::iterator it = expected.begin();
-       it != expected.end(); ++it) {
+  for (auto it = expected.begin(); it != expected.end(); ++it) {
     EXPECT_EQ(it->second, params[it->first]);
   }
 
diff --git a/chrome/browser/extensions/user_script_listener.cc b/chrome/browser/extensions/user_script_listener.cc
index 207ebb3..1c924136 100644
--- a/chrome/browser/extensions/user_script_listener.cc
+++ b/chrome/browser/extensions/user_script_listener.cc
@@ -128,7 +128,7 @@
 
   for (ProfileDataMap::const_iterator pt = profile_data_.begin();
        pt != profile_data_.end(); ++pt) {
-    for (URLPatterns::const_iterator it = pt->second.url_patterns.begin();
+    for (auto it = pt->second.url_patterns.begin();
          it != pt->second.url_patterns.end(); ++it) {
       if ((*it).MatchesURL(url)) {
         // One of the user scripts wants to inject into this request, but the
diff --git a/chrome/browser/extensions/warning_badge_service.cc b/chrome/browser/extensions/warning_badge_service.cc
index 5ac2f26..5ed35e1 100644
--- a/chrome/browser/extensions/warning_badge_service.cc
+++ b/chrome/browser/extensions/warning_badge_service.cc
@@ -141,8 +141,7 @@
 void WarningBadgeService::UpdateBadgeStatus() {
   const std::set<Warning>& warnings = GetCurrentWarnings();
   bool non_suppressed_warnings_exist = false;
-  for (std::set<Warning>::const_iterator i = warnings.begin();
-       i != warnings.end(); ++i) {
+  for (auto i = warnings.begin(); i != warnings.end(); ++i) {
     if (!base::ContainsKey(suppressed_warnings_, *i)) {
       non_suppressed_warnings_exist = true;
       break;
diff --git a/chrome/browser/extensions/webstore_inline_installer.cc b/chrome/browser/extensions/webstore_inline_installer.cc
index 2a63f93..b10f636 100644
--- a/chrome/browser/extensions/webstore_inline_installer.cc
+++ b/chrome/browser/extensions/webstore_inline_installer.cc
@@ -95,7 +95,7 @@
       *error = kInvalidWebstoreResponseError;
       return false;
     }
-    for (base::ListValue::const_iterator it = verified_sites->begin();
+    for (auto it = verified_sites->begin();
          it != verified_sites->end() && !requestor_is_ok; ++it) {
       std::string verified_site;
       if (!it->GetAsString(&verified_site)) {
diff --git a/chrome/browser/extensions/webstore_inline_installer_unittest.cc b/chrome/browser/extensions/webstore_inline_installer_unittest.cc
index 163d71a7..881528bc 100644
--- a/chrome/browser/extensions/webstore_inline_installer_unittest.cc
+++ b/chrome/browser/extensions/webstore_inline_installer_unittest.cc
@@ -97,8 +97,7 @@
     const std::string& requestor_url,
     const std::vector<std::string>& verified_sites) {
   auto sites = std::make_unique<base::ListValue>();
-  for (std::vector<std::string>::const_iterator it = verified_sites.begin();
-       it != verified_sites.end(); ++it) {
+  for (auto it = verified_sites.begin(); it != verified_sites.end(); ++it) {
     sites->AppendString(*it);
   }
   base::DictionaryValue webstore_data;
diff --git a/chrome/browser/extensions/window_controller_list.cc b/chrome/browser/extensions/window_controller_list.cc
index b9436c9..d419073 100644
--- a/chrome/browser/extensions/window_controller_list.cc
+++ b/chrome/browser/extensions/window_controller_list.cc
@@ -37,8 +37,7 @@
 }
 
 void WindowControllerList::RemoveExtensionWindow(WindowController* window) {
-  ControllerList::iterator iter = std::find(
-      windows_.begin(), windows_.end(), window);
+  auto iter = std::find(windows_.begin(), windows_.end(), window);
   if (iter != windows_.end()) {
     windows_.erase(iter);
     for (auto& observer : observers_)
@@ -59,8 +58,7 @@
     const UIThreadExtensionFunction* function,
     int id,
     WindowController::TypeFilter filter) const {
-  for (ControllerList::const_iterator iter = windows().begin();
-       iter != windows().end(); ++iter) {
+  for (auto iter = windows().begin(); iter != windows().end(); ++iter) {
     if ((*iter)->GetWindowId() == id) {
       if (windows_util::CanOperateOnWindow(function, *iter, filter))
         return *iter;
@@ -81,8 +79,7 @@
     WindowController::TypeFilter filter) const {
   WindowController* result = nullptr;
   // Returns either the focused window (if any), or the last window in the list.
-  for (ControllerList::const_iterator iter = windows().begin();
-       iter != windows().end(); ++iter) {
+  for (auto iter = windows().begin(); iter != windows().end(); ++iter) {
     if (windows_util::CanOperateOnWindow(function, *iter, filter)) {
       result = *iter;
       if (result->window()->IsActive())
diff --git a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
index dfe0f29..c9a04156 100644
--- a/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
+++ b/chrome/browser/feedback/system_logs/log_sources/chrome_internal_log_source.cc
@@ -241,8 +241,7 @@
   sync_logs->GetList(syncer::sync_ui_util::kDetailsKey, &details);
   if (!details)
     return;
-  for (base::ListValue::iterator it = details->begin();
-      it != details->end(); ++it) {
+  for (auto it = details->begin(); it != details->end(); ++it) {
     base::DictionaryValue* dict = NULL;
     if (it->GetAsDictionary(&dict)) {
       std::string title;
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 62a8ec84..52c173c 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1228,10 +1228,6 @@
     "Show Material Design icons on the New Tab Page, instead of Most Visited "
     "tiles. Implicitly enables 'ntp-ui-md'.";
 
-const char kNtpUIMdName[] = "New Tab Page Material Design UI";
-const char kNtpUIMdDescription[] =
-    "Updates the New Tab Page with Material Design elements.";
-
 const char kNumRasterThreadsName[] = "Number of raster threads";
 const char kNumRasterThreadsDescription[] =
     "Specify the number of raster threads.";
@@ -2161,6 +2157,10 @@
 const char kAndroidAutofillAccessibilityDescription[] =
     "Enable accessibility for autofill popup.";
 
+const char kAndroidSurfaceControl[] = "Use Android SurfaceControl";
+const char kAndroidSurfaceControlDescription[] =
+    "Use the SurfaceControl API for supporting overlays on Android";
+
 const char kAppNotificationStatusMessagingName[] =
     "App notification status messaging";
 const char kAppNotificationStatusMessagingDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 93245c4a..1cd3b69 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -767,9 +767,6 @@
 extern const char kNtpIconsName[];
 extern const char kNtpIconsDescription[];
 
-extern const char kNtpUIMdName[];
-extern const char kNtpUIMdDescription[];
-
 extern const char kNumRasterThreadsName[];
 extern const char kNumRasterThreadsDescription[];
 extern const char kNumRasterThreadsOne[];
@@ -1311,6 +1308,9 @@
 extern const char kAndroidPaymentAppsName[];
 extern const char kAndroidPaymentAppsDescription[];
 
+extern const char kAndroidSurfaceControl[];
+extern const char kAndroidSurfaceControlDescription[];
+
 extern const char kAppNotificationStatusMessagingName[];
 extern const char kAppNotificationStatusMessagingDescription[];
 
diff --git a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
index 7b90e3f..84889aab 100644
--- a/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
+++ b/chrome/browser/geolocation/geolocation_permission_context_unittest.cc
@@ -241,8 +241,7 @@
       content_settings->geolocation_usages_state().state_map();
   EXPECT_EQ(1U, state_map.count(requesting_frame.GetOrigin()));
   EXPECT_EQ(0U, state_map.count(requesting_frame));
-  ContentSettingsUsagesState::StateMap::const_iterator settings =
-      state_map.find(requesting_frame.GetOrigin());
+  auto settings = state_map.find(requesting_frame.GetOrigin());
   ASSERT_FALSE(settings == state_map.end())
       << "geolocation state not found " << requesting_frame;
   EXPECT_EQ(expected_content_setting, settings->second);
diff --git a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc
index 5d765a4..c0112b0a 100644
--- a/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc
+++ b/chrome/browser/guest_view/web_view/chrome_web_view_permission_helper_delegate.cc
@@ -213,8 +213,7 @@
 }
 
 int ChromeWebViewPermissionHelperDelegate::RemoveBridgeID(int bridge_id) {
-  std::map<int, int>::iterator bridge_itr =
-      bridge_id_to_request_id_map_.find(bridge_id);
+  auto bridge_itr = bridge_id_to_request_id_map_.find(bridge_id);
   if (bridge_itr == bridge_id_to_request_id_map_.end())
     return webview::kInvalidPermissionRequestID;
 
diff --git a/chrome/browser/history/redirect_browsertest.cc b/chrome/browser/history/redirect_browsertest.cc
index 3e02b81..bc313f9 100644
--- a/chrome/browser/history/redirect_browsertest.cc
+++ b/chrome/browser/history/redirect_browsertest.cc
@@ -304,8 +304,7 @@
   std::vector<GURL> redirects = GetRedirects(first_url);
   // Check to make sure our request for /title2.html doesn't get flagged
   // as a client redirect from the first (/client-redirect?) page.
-  for (std::vector<GURL>::iterator it = redirects.begin();
-       it != redirects.end(); ++it) {
+  for (auto it = redirects.begin(); it != redirects.end(); ++it) {
     if (final_url.spec() == it->spec()) {
       final_navigation_not_redirect = false;
       break;
diff --git a/chrome/browser/importer/in_process_importer_bridge.cc b/chrome/browser/importer/in_process_importer_bridge.cc
index b41f665c..46041364 100644
--- a/chrome/browser/importer/in_process_importer_bridge.cc
+++ b/chrome/browser/importer/in_process_importer_bridge.cc
@@ -31,8 +31,7 @@
     const std::vector<ImporterURLRow>& rows) {
   history::URLRows converted;
   converted.reserve(rows.size());
-  for (std::vector<ImporterURLRow>::const_iterator it = rows.begin();
-       it != rows.end(); ++it) {
+  for (auto it = rows.begin(); it != rows.end(); ++it) {
     history::URLRow row(it->url);
     row.set_title(it->title);
     row.set_visit_count(it->visit_count);
@@ -115,8 +114,8 @@
   // The first XML file represents the default search engine in Firefox 3, so we
   // need to keep it on top of the list.
   auto default_turl = search_engine_for_url.end();
-  for (std::vector<std::string>::const_iterator xml_iter =
-           xml_data.begin(); xml_iter != xml_data.end(); ++xml_iter) {
+  for (auto xml_iter = xml_data.begin(); xml_iter != xml_data.end();
+       ++xml_iter) {
     std::unique_ptr<TemplateURL> template_url = TemplateURLParser::Parse(
         UIThreadSearchTermsData(nullptr), xml_iter->data(), xml_iter->length(),
         &param_filter);
diff --git a/chrome/browser/importer/profile_writer.cc b/chrome/browser/importer/profile_writer.cc
index 3dc8c883..78bb6b0 100644
--- a/chrome/browser/importer/profile_writer.cc
+++ b/chrome/browser/importer/profile_writer.cc
@@ -133,9 +133,7 @@
   // Reorder bookmarks so that the toolbar entries come first.
   std::vector<ImportedBookmarkEntry> toolbar_bookmarks;
   std::vector<ImportedBookmarkEntry> reordered_bookmarks;
-  for (std::vector<ImportedBookmarkEntry>::const_iterator it =
-           bookmarks.begin();
-       it != bookmarks.end(); ++it) {
+  for (auto it = bookmarks.begin(); it != bookmarks.end(); ++it) {
     if (it->in_toolbar)
       toolbar_bookmarks.push_back(*it);
     else
@@ -182,8 +180,7 @@
     // Ensure any enclosing folders are present in the model.  The bookmark's
     // enclosing folder structure should be
     //   path[0] > path[1] > ... > path[size() - 1]
-    for (std::vector<base::string16>::const_iterator folder_name =
-             bookmark->path.begin();
+    for (auto folder_name = bookmark->path.begin();
          folder_name != bookmark->path.end(); ++folder_name) {
       if (bookmark->in_toolbar && parent == bookmark_bar &&
           folder_name == bookmark->path.begin()) {
@@ -220,9 +217,7 @@
 
   // In order to keep the imported-to folders from appearing in the 'recently
   // added to' combobox, reset their modified times.
-  for (std::set<const BookmarkNode*>::const_iterator i =
-           folders_added_to.begin();
-       i != folders_added_to.end(); ++i) {
+  for (auto i = folders_added_to.begin(); i != folders_added_to.end(); ++i) {
     model->ResetDateFolderModified(*i);
   }
 
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index 2e2ccbf..2db4d488 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -516,8 +516,7 @@
     std::unique_ptr<content::StreamInfo> stream) {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(request);
-  std::map<net::URLRequest*, StreamTargetInfo>::iterator ix =
-      stream_target_info_.find(request);
+  auto ix = stream_target_info_.find(request);
   CHECK(ix != stream_target_info_.end());
   bool embedded = info->GetResourceType() != content::RESOURCE_TYPE_MAIN_FRAME;
   base::PostTaskWithTraits(
diff --git a/chrome/browser/local_discovery/service_discovery_client_impl.cc b/chrome/browser/local_discovery/service_discovery_client_impl.cc
index c119c82..c23dd1d6 100644
--- a/chrome/browser/local_discovery/service_discovery_client_impl.cc
+++ b/chrome/browser/local_discovery/service_discovery_client_impl.cc
@@ -248,14 +248,14 @@
 void ServiceWatcherImpl::AddSRV(const std::string& service) {
   DCHECK(started_);
 
-  ServiceListenersMap::iterator it = services_.find(service);
+  auto it = services_.find(service);
   if (it != services_.end())
     it->second->set_has_srv(true);
 }
 
 void ServiceWatcherImpl::DeferUpdate(ServiceWatcher::UpdateType update_type,
                                      const std::string& service_name) {
-  ServiceListenersMap::iterator it = services_.find(service_name);
+  auto it = services_.find(service_name);
   if (it != services_.end() && !it->second->update_pending()) {
     it->second->set_update_pending(true);
     base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -266,7 +266,7 @@
 
 void ServiceWatcherImpl::DeliverDeferredUpdate(
     ServiceWatcher::UpdateType update_type, const std::string& service_name) {
-  ServiceListenersMap::iterator it = services_.find(service_name);
+  auto it = services_.find(service_name);
   if (it != services_.end()) {
     it->second->set_update_pending(false);
     if (!callback_.is_null())
@@ -277,7 +277,7 @@
 void ServiceWatcherImpl::RemovePTR(const std::string& service) {
   DCHECK(started_);
 
-  ServiceListenersMap::iterator it = services_.find(service);
+  auto it = services_.find(service);
   if (it != services_.end()) {
     it->second->set_has_ptr(false);
     if (!it->second->has_ptr_or_srv()) {
@@ -291,7 +291,7 @@
 void ServiceWatcherImpl::RemoveSRV(const std::string& service) {
   DCHECK(started_);
 
-  ServiceListenersMap::iterator it = services_.find(service);
+  auto it = services_.find(service);
   if (it != services_.end()) {
     it->second->set_has_srv(false);
     if (!it->second->has_ptr_or_srv()) {
diff --git a/chrome/browser/media/capture_access_handler_base.cc b/chrome/browser/media/capture_access_handler_base.cc
index 194fb46..d784a25 100644
--- a/chrome/browser/media/capture_access_handler_base.cc
+++ b/chrome/browser/media/capture_access_handler_base.cc
@@ -111,9 +111,8 @@
 void CaptureAccessHandlerBase::UpdateTrusted(
     const content::MediaStreamRequest& request,
     bool is_trusted) {
-  std::list<CaptureAccessHandlerBase::Session>::iterator it =
-      FindSession(request.render_process_id, request.render_frame_id,
-                  request.page_request_id);
+  auto it = FindSession(request.render_process_id, request.render_frame_id,
+                        request.page_request_id);
   if (it != sessions_.end()) {
     it->is_trusted = is_trusted;
     DVLOG(2) << "CaptureAccessHandlerBase::UpdateTrusted"
@@ -152,8 +151,7 @@
                                                           int render_frame_id,
                                                           int page_request_id,
                                                           bool is_secure) {
-  std::list<CaptureAccessHandlerBase::Session>::iterator it =
-      FindSession(render_process_id, render_frame_id, page_request_id);
+  auto it = FindSession(render_process_id, render_frame_id, page_request_id);
   if (it != sessions_.end()) {
     it->is_capturing_link_secure = is_secure;
     DVLOG(2) << "UpdateCapturingLinkSecured:"
diff --git a/chrome/browser/media/router/discovery/dial/dial_registry.cc b/chrome/browser/media/router/discovery/dial/dial_registry.cc
index 0cb7977..b71336b 100644
--- a/chrome/browser/media/router/discovery/dial/dial_registry.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_registry.cc
@@ -222,7 +222,7 @@
 bool DialRegistry::PruneExpiredDevices() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   bool pruned_device = false;
-  DeviceByLabelMap::iterator it = device_by_label_map_.begin();
+  auto it = device_by_label_map_.begin();
   while (it != device_by_label_map_.end()) {
     auto* device = it->second;
     if (IsDeviceExpired(*device)) {
@@ -311,8 +311,7 @@
   DCHECK(device_data->label().empty());
 
   bool did_modify_list = false;
-  DeviceByIdMap::iterator lookup_result =
-      device_by_id_map_.find(device_data->device_id());
+  auto lookup_result = device_by_id_map_.find(device_data->device_id());
 
   if (lookup_result != device_by_id_map_.end()) {
     VLOG(2) << "Found device " << device_data->device_id() << ", merging";
diff --git a/chrome/browser/media/router/discovery/mdns/dns_sd_registry.cc b/chrome/browser/media/router/discovery/mdns/dns_sd_registry.cc
index ad78d54..deb9356 100644
--- a/chrome/browser/media/router/discovery/mdns/dns_sd_registry.cc
+++ b/chrome/browser/media/router/discovery/mdns/dns_sd_registry.cc
@@ -51,8 +51,8 @@
 bool DnsSdRegistry::ServiceTypeData::UpdateService(
     bool added,
     const DnsSdService& service) {
-  DnsSdRegistry::DnsSdServiceList::iterator it = std::find_if(
-      service_list_.begin(), service_list_.end(), IsSameServiceName(service));
+  auto it = std::find_if(service_list_.begin(), service_list_.end(),
+                         IsSameServiceName(service));
   // Set to true when a service is updated in or added to the registry.
   bool updated_or_added = added;
   bool known = (it != service_list_.end());
@@ -75,8 +75,7 @@
 
 bool DnsSdRegistry::ServiceTypeData::RemoveService(
     const std::string& service_name) {
-  for (DnsSdRegistry::DnsSdServiceList::iterator it = service_list_.begin();
-       it != service_list_.end(); ++it) {
+  for (auto it = service_list_.begin(); it != service_list_.end(); ++it) {
     if ((*it).service_name == service_name) {
       service_list_.erase(it);
       return true;
diff --git a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
index c7a246d..059433b4 100644
--- a/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
+++ b/chrome/browser/media/webrtc/desktop_capture_access_handler.cc
@@ -85,9 +85,7 @@
   const extensions::AppWindowRegistry::AppWindowList& window_list =
       extensions::AppWindowRegistry::Get(web_contents->GetBrowserContext())
           ->app_windows();
-  for (extensions::AppWindowRegistry::AppWindowList::const_iterator iter =
-           window_list.begin();
-       iter != window_list.end(); ++iter) {
+  for (auto iter = window_list.begin(); iter != window_list.end(); ++iter) {
     if ((*iter)->web_contents() == web_contents)
       return (*iter)->GetNativeWindow();
   }
diff --git a/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc b/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc
index b8f307d..68ca56e3f 100644
--- a/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/webrtc/media_capture_devices_dispatcher.cc
@@ -68,7 +68,7 @@
 const content::MediaStreamDevice* FindDeviceWithId(
     const content::MediaStreamDevices& devices,
     const std::string& device_id) {
-  content::MediaStreamDevices::const_iterator iter = devices.begin();
+  auto iter = devices.begin();
   for (; iter != devices.end(); ++iter) {
     if (iter->id == device_id) {
       return &(*iter);
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list.cc b/chrome/browser/media/webrtc/native_desktop_media_list.cc
index e7bd93a..5eac54b 100644
--- a/chrome/browser/media/webrtc/native_desktop_media_list.cc
+++ b/chrome/browser/media/webrtc/native_desktop_media_list.cc
@@ -199,7 +199,7 @@
       new_image_hashes[id] = frame_hash;
 
       // Scale the image only if it has changed.
-      ImageHashesMap::iterator it = image_hashes_.find(id);
+      auto it = image_hashes_.find(id);
       if (it == image_hashes_.end() || it->second != frame_hash) {
         gfx::ImageSkia thumbnail =
             ScaleDesktopFrame(std::move(current_frame_), thumbnail_size);
diff --git a/chrome/browser/media/webrtc/native_desktop_media_list_unittest.cc b/chrome/browser/media/webrtc/native_desktop_media_list_unittest.cc
index 63ad589..d592f7a 100644
--- a/chrome/browser/media/webrtc/native_desktop_media_list_unittest.cc
+++ b/chrome/browser/media/webrtc/native_desktop_media_list_unittest.cc
@@ -117,8 +117,7 @@
 
     base::AutoLock lock(frame_values_lock_);
 
-    std::map<SourceId, int8_t>::iterator it =
-        frame_values_.find(selected_window_id_);
+    auto it = frame_values_.find(selected_window_id_);
     int8_t value = (it != frame_values_.end()) ? it->second : 0;
     std::unique_ptr<webrtc::DesktopFrame> frame(
         new webrtc::BasicDesktopFrame(webrtc::DesktopSize(10, 10)));
diff --git a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
index dde26af..c39ea5dd 100644
--- a/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
+++ b/chrome/browser/media/webrtc/permission_bubble_media_access_handler.cc
@@ -136,8 +136,7 @@
     content::WebContents* web_contents) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  std::map<content::WebContents*, RequestsQueue>::iterator it =
-      pending_requests_.find(web_contents);
+  auto it = pending_requests_.find(web_contents);
 
   if (it == pending_requests_.end() || it->second.empty()) {
     // Don't do anything if the tab was closed.
@@ -174,7 +173,7 @@
     return;
 
   bool found = false;
-  for (RequestsQueues::iterator rqs_it = pending_requests_.begin();
+  for (auto rqs_it = pending_requests_.begin();
        rqs_it != pending_requests_.end(); ++rqs_it) {
     RequestsQueue& queue = rqs_it->second;
     for (RequestsQueue::iterator it = queue.begin(); it != queue.end(); ++it) {
@@ -198,8 +197,7 @@
     std::unique_ptr<content::MediaStreamUI> ui) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  std::map<content::WebContents*, RequestsQueue>::iterator it =
-      pending_requests_.find(web_contents);
+  auto it = pending_requests_.find(web_contents);
   if (it == pending_requests_.end()) {
     // WebContents has been destroyed. Don't need to do anything.
     return;
diff --git a/chrome/browser/media/webrtc/webrtc_browsertest_perf.cc b/chrome/browser/media/webrtc/webrtc_browsertest_perf.cc
index 3d6b580b..4d9140f 100644
--- a/chrome/browser/media/webrtc/webrtc_browsertest_perf.cc
+++ b/chrome/browser/media/webrtc/webrtc_browsertest_perf.cc
@@ -237,8 +237,7 @@
   ASSERT_TRUE(pc_dict.GetDictionary("stats", &stats_dict));
   std::set<std::string> ssrc_identifiers = FindAllSsrcIdentifiers(*stats_dict);
 
-  std::set<std::string>::const_iterator ssrc_iterator =
-      ssrc_identifiers.begin();
+  auto ssrc_iterator = ssrc_identifiers.begin();
   for (; ssrc_iterator != ssrc_identifiers.end(); ++ssrc_iterator) {
     const std::string& ssrc = *ssrc_iterator;
     MaybePrintResultsForAudioSend(ssrc, pc_dict, modifier);
@@ -255,8 +254,7 @@
   ASSERT_TRUE(pc_dict.GetDictionary("stats", &stats_dict));
   std::set<std::string> ssrc_identifiers = FindAllSsrcIdentifiers(*stats_dict);
 
-  std::set<std::string>::const_iterator ssrc_iterator =
-      ssrc_identifiers.begin();
+  auto ssrc_iterator = ssrc_identifiers.begin();
   for (; ssrc_iterator != ssrc_identifiers.end(); ++ssrc_iterator) {
     const std::string& ssrc = *ssrc_iterator;
     MaybePrintResultsForAudioReceive(ssrc, pc_dict, modifier);
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
index 9dd1e0a..1665fde8 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util_unittest.cc
@@ -245,8 +245,7 @@
   for (size_t i = 0; i < arraysize(kFilteringTestCases); ++i) {
     base::FilePath::StringType name =
         base::FilePath(kFilteringTestCases[i].path).BaseName().value();
-    std::set<base::FilePath::StringType>::const_iterator found =
-        content.find(name);
+    auto found = content.find(name);
     EXPECT_EQ(kFilteringTestCases[i].visible, found != content.end());
   }
 }
diff --git a/chrome/browser/media_galleries/gallery_watch_manager.cc b/chrome/browser/media_galleries/gallery_watch_manager.cc
index a1022af..683318f 100644
--- a/chrome/browser/media_galleries/gallery_watch_manager.cc
+++ b/chrome/browser/media_galleries/gallery_watch_manager.cc
@@ -233,7 +233,7 @@
   if (observed > 0)
     preferences->RemoveGalleryChangeObserver(this);
 
-  WatchesMap::iterator it = watches_.begin();
+  auto it = watches_.begin();
   while (it != watches_.end()) {
     if (it->first.browser_context == browser_context) {
       DeactivateFileWatch(it->first, it->second);
@@ -318,7 +318,7 @@
   DCHECK(browser_context);
 
   WatchOwner owner(browser_context, extension_id, gallery_id);
-  WatchesMap::iterator it = watches_.find(owner);
+  auto it = watches_.find(owner);
   if (it != watches_.end()) {
     DeactivateFileWatch(owner, it->second);
     watches_.erase(it);
@@ -330,7 +330,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(browser_context);
 
-  WatchesMap::iterator it = watches_.begin();
+  auto it = watches_.begin();
   while (it != watches_.end()) {
     if (it->first.extension_id == extension_id) {
       DeactivateFileWatch(it->first, it->second);
@@ -374,7 +374,7 @@
 void GalleryWatchManager::DeactivateFileWatch(const WatchOwner& owner,
                                               const base::FilePath& path) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  WatchedPaths::iterator it = watched_paths_.find(path);
+  auto it = watched_paths_.find(path);
   if (it == watched_paths_.end())
     return;
 
@@ -403,7 +403,7 @@
 
 void GalleryWatchManager::OnFilePathChanged(const base::FilePath& path,
                                             bool error) {
-  WatchedPaths::iterator notification_info = watched_paths_.find(path);
+  auto notification_info = watched_paths_.find(path);
   if (notification_info == watched_paths_.end())
     return;
 
@@ -412,8 +412,7 @@
   if (error) {
     // Make a copy, as |watched_paths_| is modified as we erase watches.
     std::set<WatchOwner> owners = notification_info->second.owners;
-    for (std::set<WatchOwner>::iterator it = owners.begin(); it != owners.end();
-         ++it) {
+    for (auto it = owners.begin(); it != owners.end(); ++it) {
       Profile* profile = Profile::FromBrowserContext(it->browser_context);
       RemoveWatch(it->browser_context, it->extension_id, it->gallery_id);
       if (base::ContainsKey(observers_, profile))
@@ -477,9 +476,7 @@
     }
   }
 
-  for (std::set<std::string>::const_iterator it = extension_ids.begin();
-       it != extension_ids.end();
-       ++it) {
+  for (auto it = extension_ids.begin(); it != extension_ids.end(); ++it) {
     RemoveWatch(pref->profile(), *it, pref_id);
     if (base::ContainsKey(observers_, pref->profile()))
       observers_[pref->profile()]->OnGalleryWatchDropped(*it, pref_id);
@@ -488,7 +485,7 @@
 
 void GalleryWatchManager::OnRemovableStorageDetached(
     const storage_monitor::StorageInfo& info) {
-  WatchesMap::iterator it = watches_.begin();
+  auto it = watches_.begin();
   while (it != watches_.end()) {
     MediaGalleriesPreferences* preferences =
         g_browser_process->media_file_system_registry()->GetPreferences(
diff --git a/chrome/browser/media_galleries/media_file_system_registry.cc b/chrome/browser/media_galleries/media_file_system_registry.cc
index 5751687..82108ad 100644
--- a/chrome/browser/media_galleries/media_file_system_registry.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry.cc
@@ -310,9 +310,7 @@
     // Extract all the device ids so we can make sure they are attached.
     MediaStorageUtil::DeviceIdSet* device_ids =
         new MediaStorageUtil::DeviceIdSet;
-    for (std::set<MediaGalleryPrefId>::const_iterator id = galleries.begin();
-         id != galleries.end();
-         ++id) {
+    for (auto id = galleries.begin(); id != galleries.end(); ++id) {
       device_ids->insert(galleries_info.find(*id)->second.device_id);
     }
     MediaStorageUtil::FilterAttachedDevices(device_ids, base::Bind(
@@ -338,7 +336,7 @@
 
   // Revoke the file system for |id| if this extension has created one for |id|.
   void RevokeGalleryByPrefId(MediaGalleryPrefId id) {
-    PrefIdFsInfoMap::iterator gallery = pref_id_map_.find(id);
+    auto gallery = pref_id_map_.find(id);
     if (gallery == pref_id_map_.end())
       return;
 
@@ -384,9 +382,7 @@
       return;
     }
 
-    for (std::set<MediaGalleryPrefId>::const_iterator pref_id_it =
-             galleries.begin();
-         pref_id_it != galleries.end();
+    for (auto pref_id_it = galleries.begin(); pref_id_it != galleries.end();
          ++pref_id_it) {
       const MediaGalleryPrefId& pref_id = *pref_id_it;
       const MediaGalleryPrefInfo& gallery_info =
@@ -556,8 +552,7 @@
 
   Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
   MediaGalleriesPreferences* preferences = GetPreferences(profile);
-  MediaGalleriesPrefInfoMap::const_iterator gallery =
-      preferences->known_galleries().find(pref_id);
+  auto gallery = preferences->known_galleries().find(pref_id);
   MediaGalleryPrefIdSet permitted_galleries =
       preferences->GalleriesForExtension(*extension);
 
@@ -613,10 +608,8 @@
   // a second step.
   std::vector<InvalidatedGalleriesInfo> invalid_galleries_info;
 
-  for (ExtensionGalleriesHostMap::iterator profile_it =
-           extension_hosts_map_.begin();
-       profile_it != extension_hosts_map_.end();
-       ++profile_it) {
+  for (auto profile_it = extension_hosts_map_.begin();
+       profile_it != extension_hosts_map_.end(); ++profile_it) {
     MediaGalleriesPreferences* preferences = GetPreferences(profile_it->first);
     // If |preferences| is not yet initialized, it won't contain any galleries.
     if (!preferences->IsInitialized())
@@ -638,12 +631,11 @@
   }
 
   for (size_t i = 0; i < invalid_galleries_info.size(); i++) {
-    for (std::set<ExtensionGalleriesHost*>::const_iterator extension_host_it =
+    for (auto extension_host_it =
              invalid_galleries_info[i].extension_hosts.begin();
          extension_host_it != invalid_galleries_info[i].extension_hosts.end();
          ++extension_host_it) {
-      for (std::set<MediaGalleryPrefId>::const_iterator pref_id_it =
-               invalid_galleries_info[i].pref_ids.begin();
+      for (auto pref_id_it = invalid_galleries_info[i].pref_ids.begin();
            pref_id_it != invalid_galleries_info[i].pref_ids.end();
            ++pref_id_it) {
         (*extension_host_it)->RevokeGalleryByPrefId(*pref_id_it);
@@ -759,8 +751,7 @@
       extension_hosts_map_.find(profile);
   DCHECK(host_map_it != extension_hosts_map_.end());
   const ExtensionHostMap& extension_host_map = host_map_it->second;
-  ExtensionHostMap::const_iterator gallery_host_it =
-      extension_host_map.find(extension_id);
+  auto gallery_host_it = extension_host_map.find(extension_id);
   if (gallery_host_it == extension_host_map.end())
     return;
   gallery_host_it->second->RevokeGalleryByPrefId(pref_id);
@@ -784,8 +775,7 @@
   // even delete |extension_host_map| altogether. So do this in two loops to
   // avoid using an invalidated iterator or deleted map.
   std::vector<const extensions::Extension*> extensions;
-  for (ExtensionHostMap::const_iterator it = extension_host_map.begin();
-       it != extension_host_map.end();
+  for (auto it = extension_host_map.begin(); it != extension_host_map.end();
        ++it) {
     extensions.push_back(
         extension_registry->enabled_extensions().GetByID(it->first));
@@ -793,8 +783,7 @@
   for (size_t i = 0; i < extensions.size(); ++i) {
     if (!base::ContainsKey(extension_hosts_map_, profile))
       break;
-    ExtensionHostMap::const_iterator gallery_host_it =
-        extension_host_map.find(extensions[i]->id());
+    auto gallery_host_it = extension_host_map.find(extensions[i]->id());
     if (gallery_host_it == extension_host_map.end())
       continue;
     gallery_host_it->second->RevokeGalleryByPrefId(pref_id);
@@ -805,8 +794,7 @@
     Profile* profile,
     MediaGalleriesPreferences* preferences,
     const std::string& extension_id) {
-  ExtensionGalleriesHostMap::iterator extension_hosts =
-      extension_hosts_map_.find(profile);
+  auto extension_hosts = extension_hosts_map_.find(profile);
   // GetPreferences(), which had to be called because preferences is an
   // argument, ensures that profile is in the map.
   DCHECK(extension_hosts != extension_hosts_map_.end());
@@ -832,8 +820,7 @@
     Profile* profile, const std::string& extension_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  ExtensionGalleriesHostMap::iterator extension_hosts =
-      extension_hosts_map_.find(profile);
+  auto extension_hosts = extension_hosts_map_.find(profile);
   DCHECK(extension_hosts != extension_hosts_map_.end());
   ExtensionHostMap::size_type erase_count =
       extension_hosts->second.erase(extension_id);
diff --git a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
index 527fbfd..44376000 100644
--- a/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
+++ b/chrome/browser/media_galleries/media_file_system_registry_unittest.cc
@@ -141,8 +141,7 @@
 
 base::FilePath TestMediaFileSystemContext::GetRegisteredPath(
     const std::string& fs_name) const {
-  std::map<std::string /*fs_name*/, FSInfo>::const_iterator it =
-      file_systems_by_name_.find(fs_name);
+  auto it = file_systems_by_name_.find(fs_name);
   if (it == file_systems_by_name_.end())
     return base::FilePath();
   return it->second.path;
@@ -696,9 +695,7 @@
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
     ASSERT_GT(galleries.size(), 0U);
 #endif
-    for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin();
-         it != galleries.end();
-         ++it) {
+    for (auto it = galleries.begin(); it != galleries.end(); ++it) {
       ASSERT_EQ(MediaGalleryPrefInfo::kAutoDetected, it->second.type);
     }
   }
@@ -752,9 +749,7 @@
   const MediaGalleriesPrefInfoMap& galleries =
       profile_state->GetMediaGalleriesPrefs()->known_galleries();
   std::vector<MediaFileSystemInfo> result;
-  for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin();
-       it != galleries.end();
-       ++it) {
+  for (auto it = galleries.begin(); it != galleries.end(); ++it) {
     if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) {
       base::FilePath path = it->second.AbsolutePath();
       MediaFileSystemInfo info(path.BaseName().LossyDisplayName(), path,
@@ -769,10 +764,8 @@
 size_t MediaFileSystemRegistryTest::GetExtensionGalleriesHostCount(
     const MediaFileSystemRegistry* registry) const {
   size_t extension_galleries_host_count = 0;
-  for (MediaFileSystemRegistry::ExtensionGalleriesHostMap::const_iterator it =
-           registry->extension_hosts_map_.begin();
-       it != registry->extension_hosts_map_.end();
-       ++it) {
+  for (auto it = registry->extension_hosts_map_.begin();
+       it != registry->extension_hosts_map_.end(); ++it) {
     extension_galleries_host_count += it->second.size();
   }
   return extension_galleries_host_count;
@@ -905,8 +898,7 @@
   bool forget_gallery = false;
   MediaGalleriesPreferences* prefs = GetPreferences(profile_state->profile());
   const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries();
-  for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin();
-       it != galleries.end(); ++it) {
+  for (auto it = galleries.begin(); it != galleries.end(); ++it) {
     if (it->second.device_id == device_id) {
       prefs->ForgetGalleryById(it->first);
       forget_gallery = true;
diff --git a/chrome/browser/media_galleries/media_galleries_permission_controller.cc b/chrome/browser/media_galleries/media_galleries_permission_controller.cc
index 72bfee8..8a860a35 100644
--- a/chrome/browser/media_galleries/media_galleries_permission_controller.cc
+++ b/chrome/browser/media_galleries/media_galleries_permission_controller.cc
@@ -151,8 +151,7 @@
   if (!toggled_galleries_.empty() || !forgotten_galleries_.empty())
     return true;
 
-  for (GalleryPermissionsMap::const_iterator iter = new_galleries_.begin();
-       iter != new_galleries_.end();
+  for (auto iter = new_galleries_.begin(); iter != new_galleries_.end();
        ++iter) {
     if (iter->second.selected)
       return true;
@@ -177,8 +176,8 @@
 
   bool existing = !index;
   MediaGalleriesDialogController::Entries result;
-  for (GalleryPermissionsMap::const_iterator iter = known_galleries_.begin();
-       iter != known_galleries_.end(); ++iter) {
+  for (auto iter = known_galleries_.begin(); iter != known_galleries_.end();
+       ++iter) {
     MediaGalleryPrefId pref_id = GetPrefId(iter->first);
     if (!base::ContainsKey(forgotten_galleries_, iter->first) &&
         existing == base::ContainsKey(pref_permitted_galleries_, pref_id)) {
@@ -186,8 +185,8 @@
     }
   }
   if (existing) {
-    for (GalleryPermissionsMap::const_iterator iter = new_galleries_.begin();
-         iter != new_galleries_.end(); ++iter) {
+    for (auto iter = new_galleries_.begin(); iter != new_galleries_.end();
+         ++iter) {
       result.push_back(iter->second);
     }
   }
@@ -224,7 +223,7 @@
 void MediaGalleriesPermissionController::DidToggleEntry(
     GalleryDialogId gallery_id, bool selected) {
   // Check known galleries.
-  GalleryPermissionsMap::iterator iter = known_galleries_.find(gallery_id);
+  auto iter = known_galleries_.find(gallery_id);
   if (iter != known_galleries_.end()) {
     if (iter->second.selected == selected)
       return;
@@ -297,7 +296,7 @@
     // |known_galleries_| as well. User selecting a known gallery effectively
     // just sets the gallery to permitted.
     GalleryDialogId gallery_id = GetDialogId(gallery.pref_id);
-    GalleryPermissionsMap::iterator iter = known_galleries_.find(gallery_id);
+    auto iter = known_galleries_.find(gallery_id);
     DCHECK(iter != known_galleries_.end());
     iter->second.selected = true;
     forgotten_galleries_.erase(gallery_id);
@@ -306,8 +305,8 @@
   }
 
   // Try to find it in |new_galleries_| (user added same folder twice).
-  for (GalleryPermissionsMap::iterator iter = new_galleries_.begin();
-       iter != new_galleries_.end(); ++iter) {
+  for (auto iter = new_galleries_.begin(); iter != new_galleries_.end();
+       ++iter) {
     if (iter->second.pref_info.path == gallery.path &&
         iter->second.pref_info.device_id == gallery.device_id) {
       iter->second.selected = true;
@@ -370,8 +369,7 @@
   DCHECK(preferences_);
   const MediaGalleriesPrefInfoMap& pref_galleries =
       preferences_->known_galleries();
-  MediaGalleriesPrefInfoMap::const_iterator pref_it =
-      pref_galleries.find(pref_id);
+  auto pref_it = pref_galleries.find(pref_id);
   if (pref_it == pref_galleries.end())
     return;
   const MediaGalleryPrefInfo& gallery_info = pref_it->second;
@@ -382,9 +380,7 @@
   known_galleries_.clear();
   DCHECK(preferences_);
   const MediaGalleriesPrefInfoMap& galleries = preferences_->known_galleries();
-  for (MediaGalleriesPrefInfoMap::const_iterator iter = galleries.begin();
-       iter != galleries.end();
-       ++iter) {
+  for (auto iter = galleries.begin(); iter != galleries.end(); ++iter) {
     const MediaGalleryPrefInfo& gallery = iter->second;
     if (gallery.IsBlackListedType())
       continue;
@@ -396,9 +392,8 @@
 
   pref_permitted_galleries_ = preferences_->GalleriesForExtension(*extension_);
 
-  for (MediaGalleryPrefIdSet::iterator iter = pref_permitted_galleries_.begin();
-       iter != pref_permitted_galleries_.end();
-       ++iter) {
+  for (auto iter = pref_permitted_galleries_.begin();
+       iter != pref_permitted_galleries_.end(); ++iter) {
     GalleryDialogId gallery_id = GetDialogId(*iter);
     DCHECK(base::ContainsKey(known_galleries_, gallery_id));
     known_galleries_[gallery_id].selected = true;
@@ -460,12 +455,9 @@
   std::set<GalleryDialogId> new_galleries_to_remove;
   // Look for duplicate entries in |new_galleries_| in case one was added
   // in another dialog.
-  for (GalleryPermissionsMap::iterator it = known_galleries_.begin();
-       it != known_galleries_.end();
-       ++it) {
+  for (auto it = known_galleries_.begin(); it != known_galleries_.end(); ++it) {
     Entry& gallery = it->second;
-    for (GalleryPermissionsMap::iterator new_it = new_galleries_.begin();
-         new_it != new_galleries_.end();
+    for (auto new_it = new_galleries_.begin(); new_it != new_galleries_.end();
          ++new_it) {
       if (new_it->second.pref_info.path == gallery.pref_info.path &&
           new_it->second.pref_info.device_id == gallery.pref_info.device_id) {
@@ -477,10 +469,8 @@
       }
     }
   }
-  for (std::set<GalleryDialogId>::const_iterator it =
-           new_galleries_to_remove.begin();
-       it != new_galleries_to_remove.end();
-       ++it) {
+  for (auto it = new_galleries_to_remove.begin();
+       it != new_galleries_to_remove.end(); ++it) {
     new_galleries_.erase(*it);
   }
 
diff --git a/chrome/browser/media_galleries/media_galleries_preferences.cc b/chrome/browser/media_galleries/media_galleries_preferences.cc
index af64d12..a0bcf8d5 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences.cc
@@ -574,8 +574,7 @@
         existing_devices[i].total_size_in_bytes(), base::Time::Now(), 0, 0, 0);
   }
 
-  for (std::vector<base::Closure>::iterator iter =
-           on_initialize_callbacks_.begin();
+  for (auto iter = on_initialize_callbacks_.begin();
        iter != on_initialize_callbacks_.end(); ++iter) {
     iter->Run();
   }
@@ -590,8 +589,7 @@
   const base::ListValue* list = prefs->GetList(
       prefs::kMediaGalleriesRememberedGalleries);
   if (list) {
-    for (base::ListValue::const_iterator it = list->begin();
-         it != list->end(); ++it) {
+    for (auto it = list->begin(); it != list->end(); ++it) {
       const base::DictionaryValue* dict = NULL;
       if (!it->GetAsDictionary(&dict))
         continue;
@@ -646,8 +644,7 @@
   relative_path = relative_path.NormalizePathSeparators();
   MediaGalleryPrefIdSet galleries_on_device =
       LookUpGalleriesByDeviceId(info.device_id());
-  for (MediaGalleryPrefIdSet::const_iterator it = galleries_on_device.begin();
-       it != galleries_on_device.end();
+  for (auto it = galleries_on_device.begin(); it != galleries_on_device.end();
        ++it) {
     const MediaGalleryPrefInfo& gallery = known_galleries_.find(*it)->second;
     if (gallery.path != relative_path)
@@ -683,7 +680,7 @@
 
 MediaGalleryPrefIdSet MediaGalleriesPreferences::LookUpGalleriesByDeviceId(
     const std::string& device_id) const {
-  DeviceIdPrefIdsMap::const_iterator found = device_map_.find(device_id);
+  auto found = device_map_.find(device_id);
   if (found == device_map_.end())
     return MediaGalleryPrefIdSet();
   return found->second;
@@ -764,10 +761,8 @@
   MediaGalleryPrefIdSet galleries_on_device =
     LookUpGalleriesByDeviceId(device_id);
 
-  for (MediaGalleryPrefIdSet::const_iterator pref_id_it =
-           galleries_on_device.begin();
-       pref_id_it != galleries_on_device.end();
-       ++pref_id_it) {
+  for (auto pref_id_it = galleries_on_device.begin();
+       pref_id_it != galleries_on_device.end(); ++pref_id_it) {
     const MediaGalleryPrefInfo& existing =
         known_galleries_.find(*pref_id_it)->second;
     if (existing.path != normalized_relative_path)
@@ -827,8 +822,8 @@
         new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries));
     base::ListValue* list = update->Get();
 
-    for (base::ListValue::iterator list_iter = list->begin();
-         list_iter != list->end(); ++list_iter) {
+    for (auto list_iter = list->begin(); list_iter != list->end();
+         ++list_iter) {
       base::DictionaryValue* dict;
       MediaGalleryPrefId iter_id;
       if (list_iter->GetAsDictionary(&dict) && GetPrefId(*dict, &iter_id) &&
@@ -921,9 +916,7 @@
 
   std::vector<MediaGalleryPrefId> pref_ids;
 
-  for (base::ListValue::iterator iter = list->begin();
-       iter != list->end();
-       ++iter) {
+  for (auto iter = list->begin(); iter != list->end(); ++iter) {
     base::DictionaryValue* dict;
     MediaGalleryPrefId pref_id;
 
@@ -969,9 +962,7 @@
   update.reset();
   InitFromPrefs();
 
-  for (std::vector<MediaGalleryPrefId>::iterator iter = pref_ids.begin();
-       iter != pref_ids.end();
-       ++iter) {
+  for (auto iter = pref_ids.begin(); iter != pref_ids.end(); ++iter) {
     for (auto& observer : gallery_change_observers_)
       observer.OnGalleryInfoUpdated(this, *iter);
   }
@@ -1020,8 +1011,7 @@
   if (!base::ContainsKey(known_galleries_, id))
     return;
 
-  for (base::ListValue::iterator iter = list->begin();
-       iter != list->end(); ++iter) {
+  for (auto iter = list->begin(); iter != list->end(); ++iter) {
     base::DictionaryValue* dict;
     MediaGalleryPrefId iter_id;
     if (iter->GetAsDictionary(&dict) && GetPrefId(*dict, &iter_id) &&
@@ -1199,8 +1189,7 @@
     permissions = update.Create();
   } else {
     // If the gallery is already in the list, update the permission...
-    for (base::ListValue::iterator iter = permissions->begin();
-         iter != permissions->end(); ++iter) {
+    for (auto iter = permissions->begin(); iter != permissions->end(); ++iter) {
       base::DictionaryValue* dict = NULL;
       if (!iter->GetAsDictionary(&dict))
         continue;
@@ -1236,8 +1225,7 @@
   if (!permissions)
     return false;
 
-  for (base::ListValue::iterator iter = permissions->begin();
-       iter != permissions->end(); ++iter) {
+  for (auto iter = permissions->begin(); iter != permissions->end(); ++iter) {
     const base::DictionaryValue* dict = NULL;
     if (!iter->GetAsDictionary(&dict))
       continue;
@@ -1264,8 +1252,7 @@
     return result;
   }
 
-  for (base::ListValue::const_iterator iter = permissions->begin();
-       iter != permissions->end(); ++iter) {
+  for (auto iter = permissions->begin(); iter != permissions->end(); ++iter) {
     const base::DictionaryValue* dict = NULL;
     if (!iter->GetAsDictionary(&dict))
       continue;
diff --git a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
index 089a26e..8acf0ac4 100644
--- a/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
+++ b/chrome/browser/media_galleries/media_galleries_preferences_unittest.cc
@@ -187,9 +187,7 @@
         new ListPrefUpdate(prefs, prefs::kMediaGalleriesRememberedGalleries));
     base::ListValue* list = update->Get();
 
-    for (base::ListValue::iterator iter = list->begin();
-         iter != list->end();
-         ++iter) {
+    for (auto iter = list->begin(); iter != list->end(); ++iter) {
       base::DictionaryValue* dict;
 
       if (iter->GetAsDictionary(&dict)) {
@@ -206,9 +204,7 @@
     const MediaGalleriesPrefInfoMap& known_galleries =
         gallery_prefs_->known_galleries();
     EXPECT_EQ(expected_galleries_.size(), known_galleries.size());
-    for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin();
-         it != known_galleries.end();
-         ++it) {
+    for (auto it = known_galleries.begin(); it != known_galleries.end(); ++it) {
       VerifyGalleryInfo(it->second, it->first);
       if (it->second.type != MediaGalleryPrefInfo::kAutoDetected &&
           it->second.type != MediaGalleryPrefInfo::kBlackListed) {
@@ -245,8 +241,7 @@
 
   void VerifyGalleryInfo(const MediaGalleryPrefInfo& actual,
                          MediaGalleryPrefId expected_id) const {
-    MediaGalleriesPrefInfoMap::const_iterator in_expectation =
-      expected_galleries_.find(expected_id);
+    auto in_expectation = expected_galleries_.find(expected_id);
     ASSERT_FALSE(in_expectation == expected_galleries_.end())  << expected_id;
     EXPECT_EQ(in_expectation->second.pref_id, actual.pref_id);
     EXPECT_EQ(in_expectation->second.display_name, actual.display_name);
@@ -1252,10 +1247,7 @@
 
   const MediaGalleriesPrefInfoMap& known_galleries =
       gallery_prefs()->known_galleries();
-  for (MediaGalleriesPrefInfoMap::const_iterator it =
-           known_galleries.begin();
-       it != known_galleries.end();
-       ++it) {
+  for (auto it = known_galleries.begin(); it != known_galleries.end(); ++it) {
     if (it->second.type != MediaGalleryPrefInfo::kAutoDetected)
       continue;
 
@@ -1310,9 +1302,7 @@
 
   const MediaGalleriesPrefInfoMap& old_known_galleries =
       gallery_prefs()->known_galleries();
-  for (MediaGalleriesPrefInfoMap::const_iterator it =
-           old_known_galleries.begin();
-       it != old_known_galleries.end();
+  for (auto it = old_known_galleries.begin(); it != old_known_galleries.end();
        ++it) {
     if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) {
       std::string unique_id;
@@ -1365,9 +1355,7 @@
 
   const MediaGalleriesPrefInfoMap& known_galleries =
       gallery_prefs()->known_galleries();
-  for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin();
-       it != known_galleries.end();
-       ++it) {
+  for (auto it = known_galleries.begin(); it != known_galleries.end(); ++it) {
     if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) {
       std::string unique_id;
       if (!StorageInfo::CrackDeviceId(it->second.device_id, NULL, &unique_id))
@@ -1437,9 +1425,7 @@
 
   const MediaGalleriesPrefInfoMap& known_galleries =
       gallery_prefs()->known_galleries();
-  for (MediaGalleriesPrefInfoMap::const_iterator it = known_galleries.begin();
-       it != known_galleries.end();
-       ++it) {
+  for (auto it = known_galleries.begin(); it != known_galleries.end(); ++it) {
     std::string unique_id;
     if (!StorageInfo::CrackDeviceId(it->second.device_id, NULL, &unique_id))
       continue;
diff --git a/chrome/browser/metrics/extensions_metrics_provider.cc b/chrome/browser/metrics/extensions_metrics_provider.cc
index 892010c..715fa4c 100644
--- a/chrome/browser/metrics/extensions_metrics_provider.cc
+++ b/chrome/browser/metrics/extensions_metrics_provider.cc
@@ -474,8 +474,7 @@
     buckets.insert(HashExtension((*it)->id(), client_key));
   }
 
-  for (std::set<int>::const_iterator it = buckets.begin(); it != buckets.end();
-       ++it) {
+  for (auto it = buckets.begin(); it != buckets.end(); ++it) {
     system_profile->add_occupied_extension_bucket(*it);
   }
 }
diff --git a/chrome/browser/metrics/thread_watcher.cc b/chrome/browser/metrics/thread_watcher.cc
index 8ced33d..85bc2e5 100644
--- a/chrome/browser/metrics/thread_watcher.cc
+++ b/chrome/browser/metrics/thread_watcher.cc
@@ -402,10 +402,8 @@
   if (!g_thread_watcher_list_)
     return;
 
-  for (RegistrationList::iterator it =
-           g_thread_watcher_list_->registered_.begin();
-       g_thread_watcher_list_->registered_.end() != it;
-       ++it) {
+  for (auto it = g_thread_watcher_list_->registered_.begin();
+       g_thread_watcher_list_->registered_.end() != it; ++it) {
     if (it->second->IsVeryUnresponsive())
       ++(*unresponding_thread_count);
     else
@@ -419,10 +417,8 @@
   if (!g_thread_watcher_list_)
     return;
 
-  for (RegistrationList::iterator it =
-           g_thread_watcher_list_->registered_.begin();
-       g_thread_watcher_list_->registered_.end() != it;
-       ++it)
+  for (auto it = g_thread_watcher_list_->registered_.begin();
+       g_thread_watcher_list_->registered_.end() != it; ++it)
     it->second->WakeUp();
 }
 
@@ -557,8 +553,7 @@
     const CrashOnHangThreadMap& crash_on_hang_threads) {
   DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
 
-  CrashOnHangThreadMap::const_iterator it =
-      crash_on_hang_threads.find(thread_name);
+  auto it = crash_on_hang_threads.find(thread_name);
   bool crash_on_hang = false;
   if (it != crash_on_hang_threads.end()) {
     crash_on_hang = true;
@@ -588,7 +583,7 @@
 
   // Delete all thread watcher objects.
   while (!g_thread_watcher_list_->registered_.empty()) {
-    RegistrationList::iterator it = g_thread_watcher_list_->registered_.begin();
+    auto it = g_thread_watcher_list_->registered_.begin();
     delete it->second;
     g_thread_watcher_list_->registered_.erase(it);
   }
@@ -601,8 +596,7 @@
   DCHECK(WatchDogThread::CurrentlyOnWatchDogThread());
   if (!g_thread_watcher_list_)
     return nullptr;
-  RegistrationList::iterator it =
-      g_thread_watcher_list_->registered_.find(thread_id);
+  auto it = g_thread_watcher_list_->registered_.find(thread_id);
   if (g_thread_watcher_list_->registered_.end() == it)
     return nullptr;
   return it->second;
diff --git a/chrome/browser/metrics/thread_watcher_unittest.cc b/chrome/browser/metrics/thread_watcher_unittest.cc
index 9c25361..0eb536c 100644
--- a/chrome/browser/metrics/thread_watcher_unittest.cc
+++ b/chrome/browser/metrics/thread_watcher_unittest.cc
@@ -436,8 +436,7 @@
         tokens.token_piece(), ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
     std::string thread_name = values[0].as_string();
 
-    ThreadWatcherList::CrashOnHangThreadMap::iterator it =
-        crash_on_hang_threads.find(thread_name);
+    auto it = crash_on_hang_threads.find(thread_name);
     bool crash_on_hang = (it != crash_on_hang_threads.end());
     EXPECT_TRUE(crash_on_hang);
     EXPECT_LT(0u, it->second);
@@ -466,8 +465,7 @@
         tokens.token_piece(), ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
     std::string thread_name = values[0].as_string();
 
-    ThreadWatcherList::CrashOnHangThreadMap::iterator it =
-        crash_on_hang_threads.find(thread_name);
+    auto it = crash_on_hang_threads.find(thread_name);
 
     bool crash_on_hang = (it != crash_on_hang_threads.end());
     EXPECT_TRUE(crash_on_hang);
diff --git a/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc b/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc
index 6e6fb4f9..5d09bf1 100644
--- a/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc
+++ b/chrome/browser/nacl_host/nacl_browser_delegate_impl.cc
@@ -145,8 +145,8 @@
     return true;
   }
   bool matches = false;
-  for (std::vector<URLPattern>::iterator iter = debug_patterns_.begin();
-       iter != debug_patterns_.end(); ++iter) {
+  for (auto iter = debug_patterns_.begin(); iter != debug_patterns_.end();
+       ++iter) {
     if (iter->MatchesURL(manifest_url)) {
       matches = true;
       break;
diff --git a/chrome/browser/net/referrer.cc b/chrome/browser/net/referrer.cc
index 6595fc09..ea3a655 100644
--- a/chrome/browser/net/referrer.cc
+++ b/chrome/browser/net/referrer.cc
@@ -66,7 +66,7 @@
   if (!url.has_host())  // TODO(jar): Is this really needed????
     return;
   DCHECK(url == url.GetWithEmptyPath());
-  SubresourceMap::iterator it = find(url);
+  auto it = find(url);
   if (it != end()) {
     it->second.SubresourceIsNeeded();
     return;
@@ -88,7 +88,7 @@
   int64_t least_useful_lifetime = 0;  // Duration in milliseconds.
 
   const base::Time kNow(base::Time::Now());  // Avoid multiple calls.
-  for (SubresourceMap::iterator it = begin(); it != end(); ++it) {
+  for (auto it = begin(); it != end(); ++it) {
     int64_t lifetime = (kNow - it->second.birth_time()).InMilliseconds();
     double rate = it->second.subresource_use_rate();
     if (least_useful_url.has_host()) {
@@ -132,7 +132,7 @@
 
 std::unique_ptr<base::ListValue> Referrer::Serialize() const {
   auto subresource_list = std::make_unique<base::ListValue>();
-  for (const_iterator it = begin(); it != end(); ++it) {
+  for (auto it = begin(); it != end(); ++it) {
     subresource_list->AppendString(it->first.spec());
     subresource_list->AppendDouble(it->second.subresource_use_rate());
   }
diff --git a/chrome/browser/offline_pages/android/downloads/offline_page_share_helper.cc b/chrome/browser/offline_pages/android/downloads/offline_page_share_helper.cc
index b94122d..5827ed0 100644
--- a/chrome/browser/offline_pages/android/downloads/offline_page_share_helper.cc
+++ b/chrome/browser/offline_pages/android/downloads/offline_page_share_helper.cc
@@ -9,10 +9,10 @@
 #include "base/callback.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/android/download/download_controller_base.h"
+#include "chrome/browser/android/download/download_utils.h"
 #include "chrome/browser/offline_pages/offline_page_mhtml_archiver.h"
 #include "components/offline_pages/core/offline_page_feature.h"
 #include "components/offline_pages/core/offline_page_model.h"
-#include "jni/DownloadUtils_jni.h"
 
 using OfflineItemShareInfo = offline_items_collection::OfflineItemShareInfo;
 
@@ -30,12 +30,7 @@
 std::unique_ptr<OfflineItemShareInfo> CreateShareInfo(
     const base::FilePath& file_path) {
   auto share_info = std::make_unique<OfflineItemShareInfo>();
-  JNIEnv* env = base::android::AttachCurrentThread();
-  auto uri_jstring = Java_DownloadUtils_getUriStringForPath(
-      env,
-      base::android::ConvertUTF8ToJavaString(env, file_path.AsUTF8Unsafe()));
-  share_info->uri =
-      base::FilePath(base::android::ConvertJavaStringToUTF8(env, uri_jstring));
+  share_info->uri = DownloadUtils::GetUriStringForPath(file_path);
   return share_info;
 }
 
diff --git a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
index 42181269..c8bff7e 100644
--- a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc
@@ -79,7 +79,7 @@
     // The real GNOME Keyring doesn't match empty queries.
     if (query.empty()) return false;
     for (size_t i = 0; i < query.size(); ++i) {
-      attribute_map::const_iterator match = attributes.find(query[i].first);
+      auto match = attributes.find(query[i].first);
       if (match == attributes.end()) return false;
       if (!match->second.Equals(query[i].second)) return false;
     }
@@ -147,8 +147,7 @@
   // As a hack to ease testing migration, make it possible to reject the new
   // format for the app string. This way we can add them easily to migrate.
   if (mock_keyring_reject_local_ids) {
-    MockKeyringItem::attribute_map::iterator it =
-        item->attributes.find("application");
+    auto it = item->attributes.find("application");
     if (it != item->attributes.end() &&
         it->second.type == MockKeyringItem::ItemAttribute::STRING &&
         base::StringPiece(it->second.value_string).starts_with("chrome-")) {
@@ -235,9 +234,7 @@
       found->keyring = strdup(item->keyring.c_str());
       found->item_id = i;
       found->attributes = gnome_keyring_attribute_list_new();
-      for (MockKeyringItem::attribute_map::const_iterator it =
-               item->attributes.begin();
-           it != item->attributes.end();
+      for (auto it = item->attributes.begin(); it != item->attributes.end();
            ++it) {
         if (it->second.type == MockKeyringItem::ItemAttribute::STRING) {
           gnome_keyring_attribute_list_append_string(
@@ -423,8 +420,7 @@
   void CheckUint32Attribute(const MockKeyringItem* item,
                             const std::string& attribute,
                             uint32_t value) {
-    MockKeyringItem::attribute_map::const_iterator it =
-        item->attributes.find(attribute);
+    auto it = item->attributes.find(attribute);
     EXPECT_NE(item->attributes.end(), it);
     if (it != item->attributes.end()) {
       EXPECT_EQ(MockKeyringItem::ItemAttribute::UINT32, it->second.type);
@@ -435,8 +431,7 @@
   void CheckStringAttribute(const MockKeyringItem* item,
                             const std::string& attribute,
                             const std::string& value) {
-    MockKeyringItem::attribute_map::const_iterator it =
-        item->attributes.find(attribute);
+    auto it = item->attributes.find(attribute);
     EXPECT_NE(item->attributes.end(), it);
     if (it != item->attributes.end()) {
       EXPECT_EQ(MockKeyringItem::ItemAttribute::STRING, it->second.type);
@@ -1254,8 +1249,7 @@
   // Read the raw value back. Change the |unique_string| to
   // |unique_string_replacement| so the forms become unique.
   ASSERT_EQ(2u, mock_keyring_items.size());
-  MockKeyringItem::attribute_map::iterator it =
-      mock_keyring_items[0].attributes.find("origin_url");
+  auto it = mock_keyring_items[0].attributes.find("origin_url");
   ASSERT_NE(mock_keyring_items[0].attributes.end(), it);
   size_t position = it->second.value_string.find(unique_string);
   ASSERT_NE(std::string::npos, position) << it->second.value_string;
diff --git a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
index cd5bdeb..ccb365b 100644
--- a/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
+++ b/chrome/browser/password_manager/native_backend_kwallet_x_unittest.cc
@@ -67,17 +67,16 @@
 
   // Check for presence of a given password in a given password folder.
   bool hasEntry(const std::string& folder, const std::string& key) const {
-    Data::const_iterator it = data_.find(folder);
+    auto it = data_.find(folder);
     return it != data_.end() && it->second.find(key) != it->second.end();
   }
 
   // Get a list of password keys in a given password folder.
   bool entryList(const std::string& folder,
                  std::vector<std::string>* entries) const {
-    Data::const_iterator it = data_.find(folder);
+    auto it = data_.find(folder);
     if (it == data_.end()) return false;
-    for (Folder::const_iterator fit = it->second.begin();
-         fit != it->second.end(); ++fit)
+    for (auto fit = it->second.begin(); fit != it->second.end(); ++fit)
       entries->push_back(fit->first);
     return true;
   }
@@ -85,9 +84,9 @@
   // Read the password data for a given password in a given password folder.
   bool readEntry(const std::string& folder, const std::string& key,
                  Blob* value) const {
-    Data::const_iterator it = data_.find(folder);
+    auto it = data_.find(folder);
     if (it == data_.end()) return false;
-    Folder::const_iterator fit = it->second.find(key);
+    auto fit = it->second.find(key);
     if (fit == it->second.end()) return false;
     *value = fit->second;
     return true;
@@ -102,7 +101,7 @@
 
   // Remove the given password from the given password folder.
   bool removeEntry(const std::string& folder, const std::string& key) {
-    Data::iterator it = data_.find(folder);
+    auto it = data_.find(folder);
     if (it == data_.end()) return false;
     return it->second.erase(key) > 0;
   }
@@ -110,7 +109,7 @@
   // Write the given password data to the given password folder.
   bool writeEntry(const std::string& folder, const std::string& key,
                   const Blob& value) {
-    Data::iterator it = data_.find(folder);
+    auto it = data_.find(folder);
     if (it == data_.end()) return false;
     it->second[key] = value;
     return true;
diff --git a/chrome/browser/password_manager/password_manager_captured_sites_interactive_uitest.cc b/chrome/browser/password_manager/password_manager_captured_sites_interactive_uitest.cc
index ca239b8b..aafcefee 100644
--- a/chrome/browser/password_manager/password_manager_captured_sites_interactive_uitest.cc
+++ b/chrome/browser/password_manager/password_manager_captured_sites_interactive_uitest.cc
@@ -145,9 +145,8 @@
     }
 
     const std::vector<autofill::PasswordForm>& passwords_vector = found->second;
-    for (std::vector<autofill::PasswordForm>::const_iterator it =
-             passwords_vector.begin();
-         it != passwords_vector.end(); ++it) {
+    for (auto it = passwords_vector.begin(); it != passwords_vector.end();
+         ++it) {
       if (base::ASCIIToUTF16(username) == it->username_value &&
           base::ASCIIToUTF16(password) == it->password_value) {
         return true;
diff --git a/chrome/browser/performance_monitor/performance_monitor.cc b/chrome/browser/performance_monitor/performance_monitor.cc
index f5b2c238..3da1b8fc 100644
--- a/chrome/browser/performance_monitor/performance_monitor.cc
+++ b/chrome/browser/performance_monitor/performance_monitor.cc
@@ -127,7 +127,7 @@
     return;
   }
 
-  MetricsMap::iterator process_metrics_iter = metrics_map_.find(handle);
+  auto process_metrics_iter = metrics_map_.find(handle);
   if (process_metrics_iter == metrics_map_.end()) {
     // If we're not already watching the process, let's initialize it.
     metrics_map_[handle] = std::make_unique<ProcessMetricsHistory>();
@@ -191,7 +191,7 @@
 void PerformanceMonitor::UpdateMetricsOnIOThread(int current_update_sequence) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   // Update metrics for all watched processes; remove dead entries from the map.
-  MetricsMap::iterator iter = metrics_map_.begin();
+  auto iter = metrics_map_.begin();
   while (iter != metrics_map_.end()) {
     ProcessMetricsHistory* process_metrics = iter->second.get();
     if (process_metrics->last_update_sequence() != current_update_sequence) {
diff --git a/chrome/browser/plugins/chrome_plugin_service_filter.cc b/chrome/browser/plugins/chrome_plugin_service_filter.cc
index 3c2de25..e16e00dc 100644
--- a/chrome/browser/plugins/chrome_plugin_service_filter.cc
+++ b/chrome/browser/plugins/chrome_plugin_service_filter.cc
@@ -298,8 +298,7 @@
 const ChromePluginServiceFilter::ProcessDetails*
 ChromePluginServiceFilter::GetProcess(
     int render_process_id) const {
-  std::map<int, ProcessDetails>::const_iterator it =
-      plugin_details_.find(render_process_id);
+  auto it = plugin_details_.find(render_process_id);
   if (it == plugin_details_.end())
     return NULL;
   return &it->second;
diff --git a/chrome/browser/plugins/plugin_finder.cc b/chrome/browser/plugins/plugin_finder.cc
index 7502086..7c0dcca 100644
--- a/chrome/browser/plugins/plugin_finder.cc
+++ b/chrome/browser/plugins/plugin_finder.cc
@@ -70,7 +70,7 @@
     return;
 
   bool success = false;
-  for (base::ListValue::const_iterator mime_type_it = mime_types->begin();
+  for (auto mime_type_it = mime_types->begin();
        mime_type_it != mime_types->end(); ++mime_type_it) {
     std::string mime_type_str;
     success = mime_type_it->GetAsString(&mime_type_str);
@@ -106,8 +106,7 @@
       group_name_matcher, language_str);
   const base::ListValue* versions = NULL;
   if (plugin_dict->GetList("versions", &versions)) {
-    for (base::ListValue::const_iterator it = versions->begin();
-         it != versions->end(); ++it) {
+    for (auto it = versions->begin(); it != versions->end(); ++it) {
       const base::DictionaryValue* version_dict = NULL;
       if (!it->GetAsDictionary(&version_dict)) {
         NOTREACHED();
diff --git a/chrome/browser/plugins/plugin_finder_unittest.cc b/chrome/browser/plugins/plugin_finder_unittest.cc
index fc3a4db..0e2b2c12 100644
--- a/chrome/browser/plugins/plugin_finder_unittest.cc
+++ b/chrome/browser/plugins/plugin_finder_unittest.cc
@@ -41,7 +41,7 @@
       EXPECT_TRUE(plugin->GetBoolean("requires_authorization", &dummy_bool));
     const base::ListValue* mime_types = NULL;
     if (plugin->GetList("mime_types", &mime_types)) {
-      for (base::ListValue::const_iterator mime_type_it = mime_types->begin();
+      for (auto mime_type_it = mime_types->begin();
            mime_type_it != mime_types->end(); ++mime_type_it) {
         EXPECT_TRUE(mime_type_it->GetAsString(&dummy_str));
       }
@@ -49,7 +49,7 @@
 
     const base::ListValue* matching_mime_types = NULL;
     if (plugin->GetList("matching_mime_types", &matching_mime_types)) {
-      for (base::ListValue::const_iterator it = matching_mime_types->begin();
+      for (auto it = matching_mime_types->begin();
            it != matching_mime_types->end(); ++it) {
         EXPECT_TRUE(it->GetAsString(&dummy_str));
       }
@@ -59,8 +59,7 @@
     if (!plugin->GetList("versions", &versions))
       continue;
 
-    for (base::ListValue::const_iterator it = versions->begin();
-         it != versions->end(); ++it) {
+    for (auto it = versions->begin(); it != versions->end(); ++it) {
       const base::DictionaryValue* version_dict = NULL;
       ASSERT_TRUE(it->GetAsDictionary(&version_dict));
       EXPECT_TRUE(version_dict->GetString("version", &dummy_str));
diff --git a/chrome/browser/plugins/plugin_info_host_impl_unittest.cc b/chrome/browser/plugins/plugin_info_host_impl_unittest.cc
index b9a2351..b14c496c 100644
--- a/chrome/browser/plugins/plugin_info_host_impl_unittest.cc
+++ b/chrome/browser/plugins/plugin_info_host_impl_unittest.cc
@@ -70,8 +70,7 @@
     const GURL& url,
     const url::Origin& main_frame_origin,
     content::WebPluginInfo* plugin) {
-  std::map<base::FilePath, bool>::iterator it =
-      plugin_state_.find(plugin->path);
+  auto it = plugin_state_.find(plugin->path);
   if (it == plugin_state_.end()) {
     ADD_FAILURE() << "No plugin state for '" << plugin->path.value() << "'";
     return false;
diff --git a/chrome/browser/plugins/plugin_metadata.cc b/chrome/browser/plugins/plugin_metadata.cc
index 5106f37..b6d662b 100644
--- a/chrome/browser/plugins/plugin_metadata.cc
+++ b/chrome/browser/plugins/plugin_metadata.cc
@@ -110,8 +110,7 @@
     version = base::Version("0");
 
   // |lower_bound| returns the latest version that is not newer than |version|.
-  std::map<base::Version, SecurityStatus, VersionComparator>::const_iterator
-      it = versions_.lower_bound(version);
+  auto it = versions_.lower_bound(version);
   // If there is at least one version defined, everything older than the oldest
   // defined version is considered out-of-date.
   if (it == versions_.end())
diff --git a/chrome/browser/plugins/plugin_prefs.cc b/chrome/browser/plugins/plugin_prefs.cc
index 9e8c985..ca4b960 100644
--- a/chrome/browser/plugins/plugin_prefs.cc
+++ b/chrome/browser/plugins/plugin_prefs.cc
@@ -277,8 +277,7 @@
   }
 
   // Add the plugin groups.
-  for (std::set<base::string16>::const_iterator it = group_names.begin();
-      it != group_names.end(); ++it) {
+  for (auto it = group_names.begin(); it != group_names.end(); ++it) {
     std::unique_ptr<base::DictionaryValue> summary(new base::DictionaryValue());
     summary->SetString("name", *it);
     plugins_list->Append(std::move(summary));
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
index 2dbbf6b..e012d89 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
@@ -119,8 +119,7 @@
   }
 
   // Acknowledge all except the invalidation with the highest version.
-  syncer::SingleObjectInvalidationSet::const_reverse_iterator it =
-      list.rbegin();
+  auto it = list.rbegin();
   ++it;
   for ( ; it != list.rend(); ++it) {
     it->Acknowledge();
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
index 4fe470a..8f481f6 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator_unittest.cc
@@ -34,6 +34,7 @@
 #include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/policy/policy_constants.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -215,7 +216,8 @@
     : core_(dm_protocol::kChromeUserPolicyType,
             std::string(),
             &store_,
-            loop_.task_runner()),
+            loop_.task_runner(),
+            network::TestNetworkConnectionTracker::CreateGetter()),
       client_(nullptr),
       task_runner_(new base::TestSimpleTaskRunner()),
       object_id_a_(135, "asdf"),
diff --git a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
index d11736b..addf04e5 100644
--- a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
@@ -40,6 +40,7 @@
 #include "components/policy/core/common/cloud/mock_cloud_external_data_manager.h"
 #include "components/policy/core/common/cloud/mock_device_management_service.h"
 #include "components/policy/core/common/policy_switches.h"
+#include "content/public/browser/network_service_instance.h"
 #include "net/base/upload_bytes_element_reader.h"
 #include "net/base/upload_data_stream.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -356,7 +357,8 @@
     std::unique_ptr<MachineLevelUserCloudPolicyManager> manager =
         std::make_unique<MachineLevelUserCloudPolicyManager>(
             std::move(policy_store), nullptr, policy_dir,
-            base::ThreadTaskRunnerHandle::Get());
+            base::ThreadTaskRunnerHandle::Get(),
+            base::BindRepeating(&content::GetNetworkConnectionTracker));
     manager->Init(&schema_registry);
 
     manager->store()->RemoveObserver(&observer);
diff --git a/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.cc b/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.cc
index 1e17467..d4e88277 100644
--- a/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.cc
+++ b/chrome/browser/policy/cloud/user_cloud_policy_manager_factory.cc
@@ -20,6 +20,7 @@
 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
 #include "components/policy/core/common/cloud/user_cloud_policy_store.h"
 #include "content/public/browser/browser_context.h"
+#include "content/public/browser/network_service_instance.h"
 
 namespace policy {
 
@@ -143,10 +144,11 @@
       context->GetPath().Append(kPolicy).Append(kComponentsDir);
 
   std::unique_ptr<UserCloudPolicyManager> manager;
-  manager.reset(
-      new UserCloudPolicyManager(std::move(store), component_policy_cache_dir,
-                                 std::unique_ptr<CloudExternalDataManager>(),
-                                 base::ThreadTaskRunnerHandle::Get()));
+  manager.reset(new UserCloudPolicyManager(
+      std::move(store), component_policy_cache_dir,
+      std::unique_ptr<CloudExternalDataManager>(),
+      base::ThreadTaskRunnerHandle::Get(),
+      base::BindRepeating(&content::GetNetworkConnectionTracker)));
   manager->Init(
       SchemaRegistryServiceFactory::GetForContext(context)->registry());
   manager_wrappers_[context] = new ManagerWrapper(manager.get());
@@ -169,7 +171,7 @@
     content::BrowserContext* context) {
   if (context->IsOffTheRecord())
     return;
-  ManagerWrapperMap::iterator it = manager_wrappers_.find(context);
+  auto it = manager_wrappers_.find(context);
   // E.g. for a TestingProfile there might not be a manager created.
   if (it != manager_wrappers_.end())
     it->second->Shutdown();
@@ -177,7 +179,7 @@
 
 void UserCloudPolicyManagerFactory::BrowserContextDestroyed(
     content::BrowserContext* context) {
-  ManagerWrapperMap::iterator it = manager_wrappers_.find(context);
+  auto it = manager_wrappers_.find(context);
   if (it != manager_wrappers_.end()) {
     // The manager is not owned by the factory, so it's not deleted here.
     delete it->second;
diff --git a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
index 47b4520..196dfa2 100644
--- a/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
+++ b/chrome/browser/policy/cloud/user_policy_signin_service_unittest.cc
@@ -55,6 +55,7 @@
 #include "net/base/net_errors.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -100,7 +101,8 @@
   return new UserCloudPolicyManager(
       std::unique_ptr<UserCloudPolicyStore>(store), base::FilePath(),
       std::unique_ptr<CloudExternalDataManager>(),
-      base::ThreadTaskRunnerHandle::Get());
+      base::ThreadTaskRunnerHandle::Get(),
+      network::TestNetworkConnectionTracker::CreateGetter());
 }
 
 class UserPolicySigninServiceTest : public testing::Test {
diff --git a/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc b/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc
index 11bae1f..183792ec 100644
--- a/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc
+++ b/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc
@@ -26,6 +26,7 @@
 #include "components/policy/core/common/cloud/machine_level_user_cloud_policy_metrics.h"
 #include "components/policy/core/common/cloud/machine_level_user_cloud_policy_store.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/common/content_switches.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
@@ -111,7 +112,8 @@
               {base::MayBlock(), base::TaskPriority::BEST_EFFORT}));
   return std::make_unique<MachineLevelUserCloudPolicyManager>(
       std::move(policy_store), nullptr, policy_dir,
-      base::ThreadTaskRunnerHandle::Get());
+      base::ThreadTaskRunnerHandle::Get(),
+      base::BindRepeating(&content::GetNetworkConnectionTracker));
 }
 
 void MachineLevelUserCloudPolicyController::Init(
diff --git a/chrome/browser/policy/managed_bookmarks_policy_handler.cc b/chrome/browser/policy/managed_bookmarks_policy_handler.cc
index b112a0c..fe77569 100644
--- a/chrome/browser/policy/managed_bookmarks_policy_handler.cc
+++ b/chrome/browser/policy/managed_bookmarks_policy_handler.cc
@@ -66,7 +66,7 @@
 
 void ManagedBookmarksPolicyHandler::FilterBookmarks(base::ListValue* list) {
   // Remove any non-conforming values found.
-  base::ListValue::iterator it = list->begin();
+  auto it = list->begin();
   while (it != list->end()) {
     base::DictionaryValue* dict = NULL;
     if (!it->GetAsDictionary(&dict)) {
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 4898978..81993d0 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -2509,9 +2509,7 @@
   extensions::ProcessManager* manager =
       extensions::ProcessManager::Get(browser()->profile());
   extensions::ProcessManager::FrameSet all_frames = manager->GetAllFrames();
-  for (extensions::ProcessManager::FrameSet::const_iterator iter =
-           all_frames.begin();
-       iter != all_frames.end();) {
+  for (auto iter = all_frames.begin(); iter != all_frames.end();) {
     content::WebContents* web_contents =
         content::WebContents::FromRenderFrameHost(*iter);
     ASSERT_TRUE(web_contents);
diff --git a/chrome/browser/policy/policy_prefs_browsertest.cc b/chrome/browser/policy/policy_prefs_browsertest.cc
index 00fbc4d08..db06811c 100644
--- a/chrome/browser/policy/policy_prefs_browsertest.cc
+++ b/chrome/browser/policy/policy_prefs_browsertest.cc
@@ -268,10 +268,8 @@
     for (iterator policy = policy_test_cases_.begin();
          policy != policy_test_cases_.end();
          ++policy) {
-      for (PolicyTestCaseVector::const_iterator test_case =
-               policy->second.begin();
-           test_case != policy->second.end();
-           ++test_case) {
+      for (auto test_case = policy->second.begin();
+           test_case != policy->second.end(); ++test_case) {
         delete *test_case;
       }
     }
@@ -394,8 +392,7 @@
       ADD_FAILURE() << "Missing policy test case for: " << it.key();
     } else {
       bool has_test_case_for_this_os = false;
-      for (PolicyTestCases::PolicyTestCaseVector::const_iterator test_case =
-               policy->second.begin();
+      for (auto test_case = policy->second.begin();
            test_case != policy->second.end() && !has_test_case_for_this_os;
            ++test_case) {
         has_test_case_for_this_os |= (*test_case)->IsSupported();
@@ -463,13 +460,9 @@
   PrefService* user_prefs = browser()->profile()->GetPrefs();
 
   const PolicyTestCases test_cases;
-  for (PolicyTestCases::iterator policy = test_cases.begin();
-       policy != test_cases.end();
-       ++policy) {
-    for (PolicyTestCases::PolicyTestCaseVector::const_iterator test_case =
-             policy->second.begin();
-         test_case != policy->second.end();
-         ++test_case) {
+  for (auto policy = test_cases.begin(); policy != test_cases.end(); ++policy) {
+    for (auto test_case = policy->second.begin();
+         test_case != policy->second.end(); ++test_case) {
       const auto& pref_mappings = (*test_case)->pref_mappings();
       if (!chrome_schema.GetKnownProperty(policy->first).valid()) {
         // If the policy is supported on this platform according to the test it
diff --git a/chrome/browser/policy/profile_policy_connector_unittest.cc b/chrome/browser/policy/profile_policy_connector_unittest.cc
index 2114dcf6..d35c248d 100644
--- a/chrome/browser/policy/profile_policy_connector_unittest.cc
+++ b/chrome/browser/policy/profile_policy_connector_unittest.cc
@@ -25,6 +25,7 @@
 #include "components/policy/policy_constants.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "components/user_manager/user.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -54,7 +55,8 @@
     cloud_policy_store_.NotifyStoreLoaded();
     const auto task_runner = scoped_task_environment_.GetMainThreadTaskRunner();
     cloud_policy_manager_.reset(new CloudPolicyManager(
-        std::string(), std::string(), &cloud_policy_store_, task_runner));
+        std::string(), std::string(), &cloud_policy_store_, task_runner,
+        network::TestNetworkConnectionTracker::CreateGetter()));
     cloud_policy_manager_->Init(&schema_registry_);
   }
 
diff --git a/chrome/browser/policy/schema_registry_service_factory.cc b/chrome/browser/policy/schema_registry_service_factory.cc
index cb9dca99..201419ca 100644
--- a/chrome/browser/policy/schema_registry_service_factory.cc
+++ b/chrome/browser/policy/schema_registry_service_factory.cc
@@ -156,7 +156,7 @@
     content::BrowserContext* context) {
   if (context->IsOffTheRecord())
     return;
-  RegistryMap::iterator it = registries_.find(context);
+  auto it = registries_.find(context);
   if (it != registries_.end())
     it->second->Shutdown();
   else
diff --git a/chrome/browser/predictors/autocomplete_action_predictor.cc b/chrome/browser/predictors/autocomplete_action_predictor.cc
index 6eb7d64..9493296 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor.cc
+++ b/chrome/browser/predictors/autocomplete_action_predictor.cc
@@ -119,9 +119,8 @@
   const base::string16 lower_user_text(base::i18n::ToLower(user_text));
 
   // Merge this in to an existing match if we already saw |user_text|
-  std::vector<TransitionalMatch>::iterator match_it =
-      std::find(transitional_matches_.begin(), transitional_matches_.end(),
-                lower_user_text);
+  auto match_it = std::find(transitional_matches_.begin(),
+                            transitional_matches_.end(), lower_user_text);
 
   if (match_it == transitional_matches_.end()) {
     if (transitional_matches_size_ + lower_user_text.length() >
@@ -285,7 +284,7 @@
       row.user_text = key.user_text;
       row.url = key.url;
 
-      DBCacheMap::iterator it = db_cache_.find(key);
+      auto it = db_cache_.find(key);
       if (it == db_cache_.end()) {
         row.id = base::GenerateGUID();
         row.number_of_hits = is_hit ? 1 : 0;
@@ -367,7 +366,7 @@
   DCHECK(initialized_);
   DCHECK(id_list);
 
-  for (DBCacheMap::iterator it = db_cache_.begin(); it != db_cache_.end();) {
+  for (auto it = db_cache_.begin(); it != db_cache_.end();) {
     if (std::find_if(rows.begin(), rows.end(),
                      history::URLRow::URLRowHasURL(it->first.url)) !=
         rows.end()) {
@@ -388,8 +387,7 @@
   if (!initialized_)
     return;
 
-  for (AutocompleteActionPredictorTable::Rows::const_iterator it =
-       rows_to_add.begin(); it != rows_to_add.end(); ++it) {
+  for (auto it = rows_to_add.begin(); it != rows_to_add.end(); ++it) {
     const DBCacheKey key = { it->user_text, it->url };
     DBCacheValue value = { it->number_of_hits, it->number_of_misses };
 
@@ -400,11 +398,10 @@
     UMA_HISTOGRAM_ENUMERATION("AutocompleteActionPredictor.DatabaseAction",
                               DATABASE_ACTION_ADD, DATABASE_ACTION_COUNT);
   }
-  for (AutocompleteActionPredictorTable::Rows::const_iterator it =
-       rows_to_update.begin(); it != rows_to_update.end(); ++it) {
+  for (auto it = rows_to_update.begin(); it != rows_to_update.end(); ++it) {
     const DBCacheKey key = { it->user_text, it->url };
 
-    DBCacheMap::iterator db_it = db_cache_.find(key);
+    auto db_it = db_cache_.find(key);
     DCHECK(db_it != db_cache_.end());
     DCHECK(db_id_cache_.find(key) != db_id_cache_.end());
 
@@ -491,7 +488,7 @@
   DCHECK(url_db);
   DCHECK(id_list);
 
-  for (DBCacheMap::iterator it = db_cache_.begin(); it != db_cache_.end();) {
+  for (auto it = db_cache_.begin(); it != db_cache_.end();) {
     history::URLRow url_row;
 
     if ((url_db->GetRowForURL(it->first.url, &url_row) == 0) ||
diff --git a/chrome/browser/predictors/autocomplete_action_predictor_table.cc b/chrome/browser/predictors/autocomplete_action_predictor_table.cc
index dfa3905..7286a658 100644
--- a/chrome/browser/predictors/autocomplete_action_predictor_table.cc
+++ b/chrome/browser/predictors/autocomplete_action_predictor_table.cc
@@ -139,8 +139,7 @@
 
   if (!DB()->BeginTransaction())
     return;
-  for (Rows::const_iterator it = rows_to_add.begin();
-       it != rows_to_add.end(); ++it) {
+  for (auto it = rows_to_add.begin(); it != rows_to_add.end(); ++it) {
     sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
         base::StringPrintf(
             "INSERT INTO %s "
@@ -157,8 +156,7 @@
       return;
     }
   }
-  for (Rows::const_iterator it = rows_to_update.begin();
-       it != rows_to_update.end(); ++it) {
+  for (auto it = rows_to_update.begin(); it != rows_to_update.end(); ++it) {
     sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
         base::StringPrintf(
             "UPDATE %s "
@@ -187,8 +185,7 @@
 
   if (!DB()->BeginTransaction())
     return;
-  for (std::vector<Row::Id>::const_iterator it = id_list.begin();
-       it != id_list.end(); ++it) {
+  for (auto it = id_list.begin(); it != id_list.end(); ++it) {
     sql::Statement statement(DB()->GetCachedStatement(SQL_FROM_HERE,
         base::StringPrintf(
             "DELETE FROM %s WHERE id=?",
diff --git a/chrome/browser/predictors/loading_data_collector.cc b/chrome/browser/predictors/loading_data_collector.cc
index 6240d4a..dde78ae 100644
--- a/chrome/browser/predictors/loading_data_collector.cc
+++ b/chrome/browser/predictors/loading_data_collector.cc
@@ -204,7 +204,7 @@
   if (predictor_)
     predictor_->StartInitialization();
 
-  NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id);
+  auto nav_it = inflight_navigations_.find(navigation_id);
   if (nav_it == inflight_navigations_.end())
     return;
 
@@ -224,7 +224,7 @@
     const base::TimeTicks& first_contentful_paint) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  NavigationMap::iterator nav_it = inflight_navigations_.find(navigation_id);
+  auto nav_it = inflight_navigations_.find(navigation_id);
   if (nav_it != inflight_navigations_.end())
     nav_it->second->first_contentful_paint = first_contentful_paint;
 }
@@ -266,7 +266,7 @@
       base::TimeDelta::FromSeconds(config_.max_navigation_lifetime_seconds);
 
   base::TimeTicks time_now = base::TimeTicks::Now();
-  for (NavigationMap::iterator it = inflight_navigations_.begin();
+  for (auto it = inflight_navigations_.begin();
        it != inflight_navigations_.end();) {
     if ((it->first.tab_id == navigation_id.tab_id) ||
         (time_now - it->first.creation_time > max_navigation_age)) {
diff --git a/chrome/browser/prerender/prerender_history.cc b/chrome/browser/prerender/prerender_history.cc
index e221645..fef80168 100644
--- a/chrome/browser/prerender/prerender_history.cc
+++ b/chrome/browser/prerender/prerender_history.cc
@@ -37,9 +37,7 @@
   auto return_list = std::make_unique<base::ListValue>();
   // Javascript needs times in terms of milliseconds since Jan 1, 1970.
   base::Time epoch_start = base::Time::UnixEpoch();
-  for (std::list<Entry>::const_reverse_iterator it = entries_.rbegin();
-       it != entries_.rend();
-       ++it) {
+  for (auto it = entries_.rbegin(); it != entries_.rend(); ++it) {
     const Entry& entry = *it;
     auto entry_dict = std::make_unique<base::DictionaryValue>();
     entry_dict->SetString("url", entry.url.spec());
diff --git a/chrome/browser/prerender/prerender_link_manager.cc b/chrome/browser/prerender/prerender_link_manager.cc
index 3d37cae9..76421d7 100644
--- a/chrome/browser/prerender/prerender_link_manager.cc
+++ b/chrome/browser/prerender/prerender_link_manager.cc
@@ -212,9 +212,9 @@
 }
 
 void PrerenderLinkManager::OnChannelClosing(int child_id) {
-  std::list<LinkPrerender>::iterator next = prerenders_.begin();
+  auto next = prerenders_.begin();
   while (next != prerenders_.end()) {
-    std::list<LinkPrerender>::iterator it = next;
+    auto it = next;
     ++next;
 
     if (child_id != it->launcher_child_id)
@@ -281,8 +281,7 @@
   // Scan the list, counting how many prerenders have handles (and so were added
   // to the PrerenderManager). The count is done for the system as a whole, and
   // also per launcher.
-  for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
-       i != prerenders_.end(); ++i) {
+  for (auto i = prerenders_.begin(); i != prerenders_.end(); ++i) {
     LinkPrerender& prerender = *i;
     // Skip prerenders launched by a prerender.
     if (prerender.deferred_launcher)
@@ -416,8 +415,7 @@
 }
 
 void PrerenderLinkManager::RemovePrerender(LinkPrerender* prerender) {
-  for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
-       i != prerenders_.end(); ++i) {
+  for (auto i = prerenders_.begin(); i != prerenders_.end(); ++i) {
     LinkPrerender& current_prerender = *i;
     if (&current_prerender == prerender) {
       std::unique_ptr<PrerenderHandle> own_handle(prerender->handle);
@@ -430,8 +428,7 @@
 }
 
 void PrerenderLinkManager::CancelPrerender(LinkPrerender* prerender) {
-  for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
-       i != prerenders_.end(); ++i) {
+  for (auto i = prerenders_.begin(); i != prerenders_.end(); ++i) {
     LinkPrerender& current_prerender = *i;
     if (&current_prerender == prerender) {
       std::unique_ptr<PrerenderHandle> own_handle(prerender->handle);
@@ -457,8 +454,7 @@
 void PrerenderLinkManager::CancelPendingPrerendersForLauncher(
     PrerenderContents* launcher) {
   // Remove all pending prerenders for this launcher.
-  for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
-       i != prerenders_.end();) {
+  for (auto i = prerenders_.begin(); i != prerenders_.end();) {
     if (i->deferred_launcher == launcher) {
       DCHECK(!i->handle);
       i = prerenders_.erase(i);
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 05bb7b7..67c0109 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -420,8 +420,7 @@
   process_host->RemoveObserver(this);
   prerender_process_hosts_.erase(process_host);
 
-  PrerenderDataVector::iterator to_erase =
-      FindIteratorForPrerenderContents(prerender_data->contents());
+  auto to_erase = FindIteratorForPrerenderContents(prerender_data->contents());
   DCHECK(active_prerenders_.end() != to_erase);
   DCHECK_EQ(prerender_data, to_erase->get());
   std::unique_ptr<PrerenderContents> prerender_contents(
@@ -480,7 +479,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(entry);
 
-  PrerenderDataVector::iterator it = FindIteratorForPrerenderContents(entry);
+  auto it = FindIteratorForPrerenderContents(entry);
   DCHECK(it != active_prerenders_.end());
   to_delete_prerenders_.push_back(std::move(*it));
   active_prerenders_.erase(it);
@@ -753,8 +752,8 @@
 void PrerenderManager::SourceNavigatedAway(PrerenderData* prerender_data) {
   // The expiry time of our prerender data will likely change because of
   // this navigation. This requires a re-sort of |active_prerenders_|.
-  for (PrerenderDataVector::iterator it = active_prerenders_.begin();
-       it != active_prerenders_.end(); ++it) {
+  for (auto it = active_prerenders_.begin(); it != active_prerenders_.end();
+       ++it) {
     PrerenderData* data = it->get();
     if (data == prerender_data) {
       data->set_expiry_time(std::min(data->expiry_time(),
@@ -1044,8 +1043,8 @@
 PrerenderManager::PrerenderDataVector::iterator
 PrerenderManager::FindIteratorForPrerenderContents(
     PrerenderContents* prerender_contents) {
-  for (PrerenderDataVector::iterator it = active_prerenders_.begin();
-       it != active_prerenders_.end(); ++it) {
+  for (auto it = active_prerenders_.begin(); it != active_prerenders_.end();
+       ++it) {
     if ((*it)->contents() == prerender_contents)
       return it;
   }
diff --git a/chrome/browser/prerender/prerender_unittest.cc b/chrome/browser/prerender/prerender_unittest.cc
index dcd93df..60c1aa2c 100644
--- a/chrome/browser/prerender/prerender_unittest.cc
+++ b/chrome/browser/prerender/prerender_unittest.cc
@@ -165,7 +165,7 @@
     PrerenderData* prerender_data = FindPrerenderData(url, nullptr);
     if (!prerender_data)
       return nullptr;
-    PrerenderDataVector::iterator to_erase =
+    auto to_erase =
         FindIteratorForPrerenderContents(prerender_data->contents());
     CHECK(to_erase != active_prerenders_.end());
     std::unique_ptr<PrerenderContents> prerender_contents =
@@ -215,8 +215,7 @@
   PrerenderContents* GetPrerenderContentsForRoute(int child_id,
                                                   int route_id) const override {
     // Overridden for the PrerenderLinkManager's pending prerender logic.
-    PrerenderContentsMap::const_iterator it =
-        prerender_contents_map_.find(std::make_pair(child_id, route_id));
+    auto it = prerender_contents_map_.find(std::make_pair(child_id, route_id));
     return it != prerender_contents_map_.end() ? it->second : nullptr;
   }
 
diff --git a/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc b/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc
index 97e92266..61323d4 100644
--- a/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc
+++ b/chrome/browser/printing/cloud_print/privet_local_printer_lister.cc
@@ -55,7 +55,7 @@
   if (description.type != kPrivetTypePrinter)
     return;
 
-  DeviceContextMap::iterator it = device_contexts_.find(name);
+  auto it = device_contexts_.find(name);
   if (it != device_contexts_.end()) {
     it->second->description = description;
     delegate_->LocalPrinterChanged(name, it->second->has_local_printing,
@@ -89,7 +89,7 @@
     device_contexts_.erase(name);
     return;
   }
-  DeviceContextMap::iterator it = device_contexts_.find(http_client->GetName());
+  auto it = device_contexts_.find(http_client->GetName());
   DCHECK(it != device_contexts_.end());
 
   it->second->info_operation = http_client->CreateInfoOperation(base::Bind(
@@ -129,7 +129,7 @@
 
 const DeviceDescription* PrivetLocalPrinterLister::GetDeviceDescription(
     const std::string& name) {
-  DeviceContextMap::iterator it = device_contexts_.find(name);
+  auto it = device_contexts_.find(name);
   return (it != device_contexts_.end()) ? &it->second->description : nullptr;
 }
 
diff --git a/chrome/browser/printing/cloud_print/privet_notifications.cc b/chrome/browser/printing/cloud_print/privet_notifications.cc
index ca52127..b2b7800e 100644
--- a/chrome/browser/printing/cloud_print/privet_notifications.cc
+++ b/chrome/browser/printing/cloud_print/privet_notifications.cc
@@ -93,7 +93,7 @@
     const std::string& name,
     const DeviceDescription& description) {
   ReportPrivetUmaEvent(PRIVET_DEVICE_CHANGED);
-  DeviceContextMap::iterator it = devices_seen_.find(name);
+  auto it = devices_seen_.find(name);
   if (it != devices_seen_.end()) {
     if (!description.id.empty() &&  // Device is registered
         it->second->notification_may_be_active) {
@@ -127,7 +127,7 @@
     return;
 
   std::string name = http_client->GetName();
-  DeviceContextMap::iterator it = devices_seen_.find(name);
+  auto it = devices_seen_.find(name);
   if (it == devices_seen_.end())
     return;
 
@@ -158,7 +158,7 @@
 }
 
 void PrivetNotificationsListener::DeviceRemoved(const std::string& name) {
-  DeviceContextMap::iterator it = devices_seen_.find(name);
+  auto it = devices_seen_.find(name);
   if (it == devices_seen_.end())
     return;
 
diff --git a/chrome/browser/printing/print_job_manager.cc b/chrome/browser/printing/print_job_manager.cc
index 218ce2b82..f2fd9fb 100644
--- a/chrome/browser/printing/print_job_manager.cc
+++ b/chrome/browser/printing/print_job_manager.cc
@@ -105,8 +105,7 @@
   PrintJobs to_stop;
   to_stop.swap(current_jobs_);
 
-  for (PrintJobs::const_iterator job = to_stop.begin(); job != to_stop.end();
-       ++job) {
+  for (auto job = to_stop.begin(); job != to_stop.end(); ++job) {
     // Wait for two minutes for the print job to be spooled.
     if (wait_for_finish)
       (*job)->FlushJob(base::TimeDelta::FromMinutes(2));
diff --git a/chrome/browser/printing/print_preview_data_service.cc b/chrome/browser/printing/print_preview_data_service.cc
index ab0b698..60194e29 100644
--- a/chrome/browser/printing/print_preview_data_service.cc
+++ b/chrome/browser/printing/print_preview_data_service.cc
@@ -55,7 +55,7 @@
     if (IsInvalidIndex(index))
       return;
 
-    PreviewPageDataMap::const_iterator it = page_data_map_.find(index);
+    auto it = page_data_map_.find(index);
     if (it != page_data_map_.end())
       *data = it->second.get();
   }
@@ -108,7 +108,7 @@
     int index,
     scoped_refptr<base::RefCountedMemory>* data_bytes) const {
   *data_bytes = nullptr;
-  PreviewDataStoreMap::const_iterator it = data_store_map_.find(preview_ui_id);
+  auto it = data_store_map_.find(preview_ui_id);
   if (it != data_store_map_.end())
     it->second->GetPreviewDataForIndex(index, data_bytes);
 }
diff --git a/chrome/browser/printing/print_preview_dialog_controller.cc b/chrome/browser/printing/print_preview_dialog_controller.cc
index ab799f64..2b7cd45 100644
--- a/chrome/browser/printing/print_preview_dialog_controller.cc
+++ b/chrome/browser/printing/print_preview_dialog_controller.cc
@@ -198,7 +198,7 @@
     WebContents* contents) const {
   // |preview_dialog_map_| is keyed by the preview dialog, so if find()
   // succeeds, then |contents| is the preview dialog.
-  PrintPreviewDialogMap::const_iterator it = preview_dialog_map_.find(contents);
+  auto it = preview_dialog_map_.find(contents);
   if (it != preview_dialog_map_.end())
     return contents;
 
@@ -216,7 +216,7 @@
 
 WebContents* PrintPreviewDialogController::GetInitiator(
     WebContents* preview_dialog) {
-  PrintPreviewDialogMap::iterator it = preview_dialog_map_.find(preview_dialog);
+  auto it = preview_dialog_map_.find(preview_dialog);
   return (it != preview_dialog_map_.end()) ? it->second : nullptr;
 }
 
@@ -256,7 +256,7 @@
 
 void PrintPreviewDialogController::EraseInitiatorInfo(
     WebContents* preview_dialog) {
-  PrintPreviewDialogMap::iterator it = preview_dialog_map_.find(preview_dialog);
+  auto it = preview_dialog_map_.find(preview_dialog);
   if (it == preview_dialog_map_.end())
     return;
 
@@ -272,7 +272,7 @@
   // |preview_dialog_map_| because RemoveFoo() can change |preview_dialog_map_|.
   std::vector<WebContents*> closed_initiators;
   std::vector<WebContents*> closed_preview_dialogs;
-  for (PrintPreviewDialogMap::iterator iter = preview_dialog_map_.begin();
+  for (auto iter = preview_dialog_map_.begin();
        iter != preview_dialog_map_.end(); ++iter) {
     WebContents* preview_dialog = iter->first;
     WebContents* initiator = iter->second;
diff --git a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
index 9e86ff0..23b6b3e 100644
--- a/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
+++ b/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc
@@ -420,8 +420,8 @@
     const uint8_t kColorByte = 255;
     std::vector<uint8_t> filled_bitmap(
         desired_width * kColorChannels * height, kColorByte);
-    std::vector<uint8_t>::iterator filled_bitmap_it = filled_bitmap.begin();
-    std::vector<uint8_t>::iterator bitmap_it = bitmap->begin();
+    auto filled_bitmap_it = filled_bitmap.begin();
+    auto bitmap_it = bitmap->begin();
 
     for (int i = 0; i < height; ++i) {
       std::copy(
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index f241664a..66542239 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -777,8 +777,7 @@
       settings->GetUrlsToRestoreOnStartup());
   EXPECT_TRUE(startup_list);
   std::vector<std::string> startup_pages;
-  for (base::ListValue::iterator i = startup_list->begin();
-       i != startup_list->end(); ++i) {
+  for (auto i = startup_list->begin(); i != startup_list->end(); ++i) {
     std::string url;
     EXPECT_TRUE(i->GetAsString(&url));
     startup_pages.push_back(url);
diff --git a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
index dcc0460..7f1740b 100644
--- a/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
+++ b/chrome/browser/profile_resetter/resettable_settings_snapshot.cc
@@ -250,8 +250,7 @@
   // Add snapshot data.
   const std::vector<GURL>& urls = snapshot.startup_urls();
   std::string startup_urls;
-  for (std::vector<GURL>::const_iterator i = urls.begin();
-       i != urls.end(); ++i) {
+  for (auto i = urls.begin(); i != urls.end(); ++i) {
     if (!startup_urls.empty())
       startup_urls += ' ';
     startup_urls += i->host();
@@ -317,8 +316,7 @@
   if (snapshot.shortcuts_determined()) {
     base::string16 shortcut_targets;
     const std::vector<ShortcutCommand>& shortcuts = snapshot.shortcuts();
-    for (std::vector<ShortcutCommand>::const_iterator i =
-         shortcuts.begin(); i != shortcuts.end(); ++i) {
+    for (auto i = shortcuts.begin(); i != shortcuts.end(); ++i) {
       if (!shortcut_targets.empty())
         shortcut_targets += base::ASCIIToUTF16("\n");
       shortcut_targets += base::ASCIIToUTF16("chrome.exe ");
@@ -339,8 +337,7 @@
   const ResettableSettingsSnapshot::ExtensionList& extensions =
       snapshot.enabled_extensions();
   std::string extension_names;
-  for (ResettableSettingsSnapshot::ExtensionList::const_iterator i =
-       extensions.begin(); i != extensions.end(); ++i) {
+  for (auto i = extensions.begin(); i != extensions.end(); ++i) {
     if (!extension_names.empty())
       extension_names += '\n';
     extension_names += i->second;
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc
index de26825..c19b171 100644
--- a/chrome/browser/profiles/off_the_record_profile_io_data.cc
+++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -114,8 +114,7 @@
 
   // Keep a map of request context getters, one per requested app ID.
   StoragePartitionDescriptor descriptor(partition_path, in_memory);
-  ChromeURLRequestContextGetterMap::iterator iter =
-      app_request_context_getter_map_.find(descriptor);
+  auto iter = app_request_context_getter_map_.find(descriptor);
   CHECK(iter != app_request_context_getter_map_.end());
   return iter->second;
 }
@@ -189,8 +188,7 @@
 OffTheRecordProfileIOData::Handle::GetAllContextGetters() {
   std::unique_ptr<ChromeURLRequestContextGetterVector> context_getters(
       new ChromeURLRequestContextGetterVector());
-  ChromeURLRequestContextGetterMap::iterator iter =
-      app_request_context_getter_map_.begin();
+  auto iter = app_request_context_getter_map_.begin();
   for (; iter != app_request_context_getter_map_.end(); ++iter)
     context_getters->push_back(iter->second);
 
diff --git a/chrome/browser/profiles/profile_destroyer.cc b/chrome/browser/profiles/profile_destroyer.cc
index f84d43f..df97a1db 100644
--- a/chrome/browser/profiles/profile_destroyer.cc
+++ b/chrome/browser/profiles/profile_destroyer.cc
@@ -105,8 +105,8 @@
   DCHECK(profile);
   DCHECK(profile->IsOffTheRecord());
   if (pending_destroyers_) {
-    for (DestroyerSet::iterator i = pending_destroyers_->begin();
-         i != pending_destroyers_->end(); ++i) {
+    for (auto i = pending_destroyers_->begin(); i != pending_destroyers_->end();
+         ++i) {
       if ((*i)->profile_ == profile) {
         // We want to signal this in debug builds so that we don't lose sight of
         // these potential leaks, but we handle it in release so that we don't
@@ -126,7 +126,7 @@
   if (pending_destroyers_ == NULL)
     pending_destroyers_ = new DestroyerSet;
   pending_destroyers_->insert(this);
-  for (HostSet::iterator i = hosts->begin(); i != hosts->end(); ++i) {
+  for (auto i = hosts->begin(); i != hosts->end(); ++i) {
     (*i)->AddObserver(this);
     // For each of the observations, we bump up our reference count.
     // It will go back to 0 and free us when all hosts are terminated.
@@ -156,7 +156,7 @@
                            << "destroyed early enough!";
 #endif  // NDEBUG
   DCHECK(pending_destroyers_ != NULL);
-  DestroyerSet::iterator iter = pending_destroyers_->find(this);
+  auto iter = pending_destroyers_->find(this);
   DCHECK(iter != pending_destroyers_->end());
   pending_destroyers_->erase(iter);
   if (pending_destroyers_->empty()) {
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc
index 3bd55049..790785ed 100644
--- a/chrome/browser/profiles/profile_impl_io_data.cc
+++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -282,8 +282,7 @@
 
   // Keep a map of request context getters, one per requested storage partition.
   StoragePartitionDescriptor descriptor(partition_path, in_memory);
-  ChromeURLRequestContextGetterMap::iterator iter =
-      app_request_context_getter_map_.find(descriptor);
+  auto iter = app_request_context_getter_map_.find(descriptor);
   if (iter != app_request_context_getter_map_.end())
     return iter->second;
 
@@ -326,8 +325,7 @@
 
   // Keep a map of request context getters, one per requested storage partition.
   StoragePartitionDescriptor descriptor(partition_path, in_memory);
-  ChromeURLRequestContextGetterMap::iterator iter =
-      isolated_media_request_context_getter_map_.find(descriptor);
+  auto iter = isolated_media_request_context_getter_map_.find(descriptor);
   if (iter != isolated_media_request_context_getter_map_.end())
     return iter->second;
 
diff --git a/chrome/browser/profiles/profile_info_cache.cc b/chrome/browser/profiles/profile_info_cache.cc
index 98bd76a..928a78b9 100644
--- a/chrome/browser/profiles/profile_info_cache.cc
+++ b/chrome/browser/profiles/profile_info_cache.cc
@@ -687,8 +687,7 @@
 
   // Remove and reinsert key in |sorted_keys_| to alphasort.
   std::string key = CacheKeyFromProfilePath(GetPathOfProfileAtIndex(index));
-  std::vector<std::string>::iterator key_it =
-      std::find(sorted_keys_.begin(), sorted_keys_.end(), key);
+  auto key_it = std::find(sorted_keys_.begin(), sorted_keys_.end(), key);
   DCHECK(key_it != sorted_keys_.end());
   sorted_keys_.erase(key_it);
   sorted_keys_.insert(FindPositionForProfile(key, name), key);
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc
index e9104165..79dbe971 100644
--- a/chrome/browser/profiles/profile_io_data.cc
+++ b/chrome/browser/profiles/profile_io_data.cc
@@ -633,8 +633,7 @@
     domain_reliability_monitor_unowned_->Shutdown();
 
   current_context = 0;
-  for (URLRequestContextMap::iterator it =
-           isolated_media_request_context_map_.begin();
+  for (auto it = isolated_media_request_context_map_.begin();
        it != isolated_media_request_context_map_.end(); ++it) {
     if (current_context < kMaxCachedContexts) {
       CHECK_EQ(media_context_cache[current_context], it->second);
@@ -700,9 +699,7 @@
 void ProfileIOData::InstallProtocolHandlers(
     net::URLRequestJobFactoryImpl* job_factory,
     content::ProtocolHandlerMap* protocol_handlers) {
-  for (content::ProtocolHandlerMap::iterator it =
-           protocol_handlers->begin();
-       it != protocol_handlers->end();
+  for (auto it = protocol_handlers->begin(); it != protocol_handlers->end();
        ++it) {
     bool set_protocol =
         job_factory->SetProtocolHandler(it->first, std::move(it->second));
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc
index 9d1f4de..ff55c4c 100644
--- a/chrome/browser/profiles/profile_manager.cc
+++ b/chrome/browser/profiles/profile_manager.cc
@@ -574,7 +574,7 @@
   }
 
   // Create the profile if needed and collect its ProfileInfo.
-  ProfilesInfoMap::iterator iter = profiles_info_.find(profile_path);
+  auto iter = profiles_info_.find(profile_path);
   ProfileInfo* info = NULL;
 
   if (iter != profiles_info_.end()) {
@@ -616,8 +616,8 @@
 }
 
 bool ProfileManager::IsValidProfile(const void* profile) {
-  for (ProfilesInfoMap::iterator iter = profiles_info_.begin();
-       iter != profiles_info_.end(); ++iter) {
+  for (auto iter = profiles_info_.begin(); iter != profiles_info_.end();
+       ++iter) {
     if (iter->second->created) {
       Profile* candidate = iter->second->profile.get();
       if (candidate == profile ||
@@ -732,8 +732,8 @@
 
 std::vector<Profile*> ProfileManager::GetLoadedProfiles() const {
   std::vector<Profile*> profiles;
-  for (ProfilesInfoMap::const_iterator iter = profiles_info_.begin();
-       iter != profiles_info_.end(); ++iter) {
+  for (auto iter = profiles_info_.begin(); iter != profiles_info_.end();
+       ++iter) {
     if (iter->second->created)
       profiles.push_back(iter->second->profile.get());
   }
@@ -1238,7 +1238,7 @@
                                       bool is_new_profile) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  ProfilesInfoMap::iterator iter = profiles_info_.find(profile->GetPath());
+  auto iter = profiles_info_.find(profile->GetPath());
   DCHECK(iter != profiles_info_.end());
   ProfileInfo* info = iter->second.get();
 
@@ -1642,7 +1642,7 @@
 
 ProfileManager::ProfileInfo* ProfileManager::GetProfileInfoByPath(
     const base::FilePath& path) const {
-  ProfilesInfoMap::const_iterator iter = profiles_info_.find(path);
+  auto iter = profiles_info_.find(path);
   return (iter == profiles_info_.end()) ? NULL : iter->second.get();
 }
 
diff --git a/chrome/browser/profiles/profiles_state.cc b/chrome/browser/profiles/profiles_state.cc
index 5b397f53..1842c5ed 100644
--- a/chrome/browser/profiles/profiles_state.cc
+++ b/chrome/browser/profiles/profiles_state.cc
@@ -157,7 +157,7 @@
   DCHECK(identity_manager->HasPrimaryAccount());
   AccountInfo primary_account = identity_manager->GetPrimaryAccountInfo();
 
-  std::vector<AccountInfo>::iterator primary_index = std::find_if(
+  auto primary_index = std::find_if(
       accounts.begin(), accounts.end(),
       [&primary_account](const AccountInfo& account_info) {
         return account_info.account_id == primary_account.account_id;
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 1da1006..85b09610 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -680,9 +680,7 @@
   std::vector<base::string16> sorted_menu_titles;
   std::map<base::string16, std::vector<const Extension*>>
       title_to_extensions_map;
-  for (std::set<MenuItem::ExtensionKey>::iterator iter = ids.begin();
-       iter != ids.end();
-       ++iter) {
+  for (auto iter = ids.begin(); iter != ids.end(); ++iter) {
     const Extension* extension =
         service->GetExtensionById(iter->extension_id, false);
     // Platform apps have their context menus created directly in
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
index a4e9216..449100e3 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu_unittest.cc
@@ -36,7 +36,7 @@
 #include "content/public/test/web_contents_tester.h"
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/common/url_pattern.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/test/test_shared_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/web/web_context_menu_data.h"
 #include "url/gurl.h"
@@ -440,7 +440,7 @@
     settings->InitDataReductionProxySettings(
         drp_test_context_->io_data(), drp_test_context_->pref_service(),
         drp_test_context_->request_context_getter(),
-        nullptr /* url_loader_factory */,
+        base::MakeRefCounted<network::TestSharedURLLoaderFactory>(),
         std::make_unique<data_reduction_proxy::DataStore>(),
         base::ThreadTaskRunnerHandle::Get(),
         base::ThreadTaskRunnerHandle::Get());
diff --git a/chrome/browser/renderer_context_menu/spelling_menu_observer.cc b/chrome/browser/renderer_context_menu/spelling_menu_observer.cc
index 538bbde..02d63a50 100644
--- a/chrome/browser/renderer_context_menu/spelling_menu_observer.cc
+++ b/chrome/browser/renderer_context_menu/spelling_menu_observer.cc
@@ -313,9 +313,7 @@
   if (results.empty()) {
     succeeded_ = false;
   } else {
-    typedef std::vector<SpellCheckResult> SpellCheckResults;
-    for (SpellCheckResults::const_iterator it = results.begin();
-         it != results.end(); ++it) {
+    for (auto it = results.begin(); it != results.end(); ++it) {
       // If there's more than one replacement, we can't automatically apply it
       if (it->replacements.size() == 1)
         result_.replace(it->location, it->length, it->replacements[0]);
diff --git a/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc b/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc
index f6dbeff..80fd492 100644
--- a/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc
+++ b/chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc
@@ -87,9 +87,7 @@
 void WriteDataToPickle(const std::map<base::string16, std::string>& data,
                        base::Pickle* pickle) {
   pickle->WriteUInt32(data.size());
-  for (std::map<base::string16, std::string>::const_iterator it = data.begin();
-       it != data.end();
-       ++it) {
+  for (auto it = data.begin(); it != data.end(); ++it) {
     pickle->WriteString16(it->first);
     pickle->WriteString(it->second);
   }
diff --git a/chrome/browser/resource_coordinator/render_process_probe.cc b/chrome/browser/resource_coordinator/render_process_probe.cc
index f3821a1..988ed9a 100644
--- a/chrome/browser/resource_coordinator/render_process_probe.cc
+++ b/chrome/browser/resource_coordinator/render_process_probe.cc
@@ -83,7 +83,7 @@
 
   StartMemoryMeasurement(collection_start_time);
 
-  RenderProcessInfoMap::iterator iter = render_process_info_map_.begin();
+  auto iter = render_process_info_map_.begin();
   while (iter != render_process_info_map_.end()) {
     auto& render_process_info = iter->second;
 
diff --git a/chrome/browser/resource_coordinator/tab_memory_metrics_reporter.cc b/chrome/browser/resource_coordinator/tab_memory_metrics_reporter.cc
index 99bee4e..544bb2c7 100644
--- a/chrome/browser/resource_coordinator/tab_memory_metrics_reporter.cc
+++ b/chrome/browser/resource_coordinator/tab_memory_metrics_reporter.cc
@@ -109,7 +109,7 @@
 
   // Extract all WebContentsData whose next_emit_time have expired,
   // and emit metrics for them.
-  std::set<WebContentsData>::iterator it = monitored_contents_.begin();
+  auto it = monitored_contents_.begin();
   while (it != monitored_contents_.end() &&
          it->next_emit_time <= current_time) {
     if (EmitMemoryMetricsAfterPageLoaded(*it))
diff --git a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
index 73f06aaf..ca5ab0b 100644
--- a/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
+++ b/chrome/browser/resources/chromeos/select_to_speak/select_to_speak.js
@@ -128,8 +128,8 @@
    * Called in response to our hit test after the mouse is released,
    * when the user is in a mode where select-to-speak is capturing
    * mouse events (for example holding down Search).
-   *
    * @param {!AutomationEvent} evt The automation event.
+   * @private
    */
   onAutomationHitTest_: function(evt) {
     // Walk up to the nearest window, web area, toolbar, or dialog that the
@@ -175,6 +175,7 @@
   /**
    * Queues up selected text for reading by finding the Position objects
    * representing the selection.
+   * @private
    */
   requestSpeakSelectedText_: function(focusedNode) {
     // If nothing is selected, return early.
@@ -249,6 +250,7 @@
    * @param {NodeUtils.Position} lastPosition The last position at which to stop
    *     reading.
    * @param {AutomationNode} focusedNode The node with user focus.
+   * @private
    */
   readNodesInSelection_: function(firstPosition, lastPosition, focusedNode) {
     let nodes = [];
@@ -332,6 +334,7 @@
    * Gets ready to cancel future scrolling to offscreen nodes as soon as
    * a user-initiated scroll is done.
    * @param {AutomationNode=} root The root node to listen for events on.
+   * @private
    */
   initializeScrollingToOffscreenNodes_: function(root) {
     if (!root) {
@@ -355,6 +358,7 @@
   /**
    * Plays a tone to let the user know they did the correct
    * keystroke but nothing was selected.
+   * @private
    */
   onNullSelection_: function() {
     this.null_selection_tone_.play();
@@ -367,6 +371,7 @@
    * If speech was not in progress, i.e. if the user was drawing
    * a focus ring on the screen, this still clears the visual
    * focus ring.
+   * @private
    */
   stopAll_: function() {
     chrome.tts.stop();
@@ -377,6 +382,7 @@
   /**
    * Clears the current focus ring and node, but does
    * not stop the speech.
+   * @private
    */
   clearFocusRingAndNode_: function() {
     this.clearFocusRing_();
@@ -392,6 +398,7 @@
   /**
    * Clears the focus ring, but does not clear the current
    * node.
+   * @private
    */
   clearFocusRing_: function() {
     chrome.accessibilityPrivate.setFocusRing([]);
@@ -426,6 +433,7 @@
 
   /**
    * Set up event listeners user input.
+   * @private
    */
   setUpEventListeners_: function() {
     this.inputHandler_ = new InputHandler({
@@ -513,6 +521,7 @@
    * with any particular nodes, so this does not do any work around drawing
    * focus rings, unlike startSpeechQueue_ below.
    * @param {string} text The text to speak.
+   * @private
    */
   startSpeech_: function(text) {
     this.prepareForSpeech_();
@@ -537,6 +546,7 @@
    * at which to start speaking. If this is not passed, will start at 0.
    * @param {number=} opt_endIndex The index into the last node's text
    * at which to end speech. If this is not passed, will stop at the end.
+   * @private
    */
   startSpeechQueue_: function(nodes, opt_startIndex, opt_endIndex) {
     this.prepareForSpeech_();
@@ -652,6 +662,7 @@
 
   /**
    * Prepares for speech. Call once before chrome.tts.speak is called.
+   * @private
    */
   prepareForSpeech_: function() {
     this.cancelIfSpeaking_(true /* clear the focus ring */);
@@ -666,6 +677,7 @@
   /**
    * Updates the state.
    * @param {!chrome.accessibilityPrivate.SelectToSpeakState} state
+   * @private
    */
   onStateChanged_: function(state) {
     if (this.state_ != state) {
@@ -693,6 +705,7 @@
    * where cancel is called twice.
    * @param {boolean} clearFocusRing Whether to clear the focus ring
    *    as well.
+   * @private
    */
   cancelIfSpeaking_: function(clearFocusRing) {
     chrome.tts.isSpeaking(MetricsUtils.recordCancelIfSpeaking);
@@ -711,6 +724,7 @@
    * @param {ParagraphUtils.NodeGroupItem} nodeGroupItem The node to use for
    *     updates.
    * @param {boolean} inForeground Whether the node is in the foreground window.
+   * @private
    */
   updateFromNodeState_: function(nodeGroupItem, inForeground) {
     switch (NodeUtils.getNodeState(nodeGroupItem.node)) {
@@ -749,6 +763,7 @@
    *
    * @param {ParagraphUtils.NodeGroupItem} nodeGroupItem The node to use for
    *    updates.
+   * @private
    */
   updateHighlightAndFocus_: function(nodeGroupItem) {
     if (!this.visible_) {
@@ -798,6 +813,7 @@
 
   /**
    * Tests the active node to make sure the bounds are drawn correctly.
+   * @private
    */
   testCurrentNode_: function() {
     if (this.currentNode_ == null) {
@@ -822,6 +838,7 @@
   /**
    * Checks that the current node is in the same window as the HitTest node.
    * Uses this information to update Select-To-Speak from node state.
+   * @private
    */
   onHitTestCheckCurrentNodeMatches_: function(evt) {
     if (this.currentNode_ == null) {
@@ -856,6 +873,7 @@
    * This takes precedence over the charIndex.
    * @param {number=} opt_endIndex The index at which to end the highlight. This
    * takes precedence over the next word end.
+   * @private
    */
   updateNodeHighlight_: function(
       text, charIndex, opt_startIndex, opt_endIndex) {
@@ -895,6 +913,7 @@
    * Fires a mock key down event for testing.
    * @param {!Event} event The fake key down event to fire. The object
    * must contain at minimum a keyCode.
+   * @protected
    */
   fireMockKeyDownEvent: function(event) {
     this.inputHandler_.onKeyDown_(event);
@@ -904,6 +923,7 @@
    * Fires a mock key up event for testing.
    * @param {!Event} event The fake key up event to fire. The object
    * must contain at minimum a keyCode.
+   * @protected
    */
   fireMockKeyUpEvent: function(event) {
     this.inputHandler_.onKeyUp_(event);
@@ -913,6 +933,7 @@
    * Fires a mock mouse down event for testing.
    * @param {!Event} event The fake mouse down event to fire. The object
    * must contain at minimum a screenX and a screenY.
+   * @protected
    */
   fireMockMouseDownEvent: function(event) {
     this.inputHandler_.onMouseDown_(event);
@@ -922,6 +943,7 @@
    * Fires a mock mouse up event for testing.
    * @param {!Event} event The fake mouse up event to fire. The object
    * must contain at minimum a screenX and a screenY.
+   * @protected
    */
   fireMockMouseUpEvent: function(event) {
     this.inputHandler_.onMouseUp_(event);
@@ -931,6 +953,7 @@
    * Function to be called when a state change request is received from the
    * accessibilityPrivate API.
    * @type {?function()}
+   * @protected
    */
   onStateChangeRequestedCallbackForTest_: null,
 };
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 1f94939f..003e077 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -292,32 +292,22 @@
 }
 
 #fakebox {
-  background-color: #fff;
-  border-radius: 2px;
-  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08);
+  background-color: rgb(241, 243, 244);
+  border-radius: 22px;
   cursor: text;
   font-size: 18px;
   height: 44px;
   line-height: 36px;
-  margin: 0 calc(var(--tile-margin) / 2 + 1px) 0 calc(var(--tile-margin) / 2);
-  outline: none;
-  position: relative;
-  transition: box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1);
-}
-
-.md #fakebox {
-  background-color: rgb(241, 243, 244);
-  border-radius: 22px;
-  box-shadow: none;
   margin: 0 auto;
   max-width: 560px;
   opacity: 1;
+  position: relative;
   transition: background-color 300ms ease-in-out;
   /* Transition should be similar to .mv-tile/.md-tile opacity transition. */
   transition: opacity 200ms;
 }
 
-.md #fakebox:hover {
+#fakebox:hover {
   background-color: rgb(232, 234, 237);
 }
 
@@ -325,50 +315,33 @@
   display: none;
 }
 
-#fakebox:hover,
-body.fakebox-focused #fakebox {
-  box-shadow: 0 3px 8px 0 rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.08);
-}
-
-.md #fakebox:hover,
-body.md.fakebox-focused #fakebox {
-  box-shadow: none;
-}
-
 #fakebox > input {
   bottom: 0;
   box-sizing: border-box;
   left: 0;
   margin: 0;
   opacity: 0;
-  padding-left: 8px;
+  padding-left: 20px;
   position: absolute;
   top: 0;
   width: 100%;
 }
 
-.md #fakebox > input {
-  padding-left: 20px;
-}
-
 html[dir=rtl] #fakebox > input {
   padding-left: 0;
-  padding-right: 8px;
-  right: 0;
-}
-
-html[dir=rtl] .md  #fakebox > input {
   padding-right: 20px;
+  right: 0;
 }
 
 #fakebox-text {
   bottom: 4px;
-  color: rgba(0, 0, 0, 0.42);
-  font-family: arial, sans-serif;
-  font-size: 16px;
-  left: 13px;
+  color: rgb(128, 134, 139);
+  font-family: 'Roboto', arial, sans-serif;
+  font-size: 14px;
+  left: 0;
   margin-top: 1px;
   overflow: hidden;
+  padding-left: 20px;
   position: absolute;
   right: 13px;
   text-align: initial;
@@ -379,20 +352,7 @@
   white-space: nowrap;
 }
 
-.md #fakebox-text {
-  color: rgb(128, 134, 139);
-  font-family: 'Roboto', arial, sans-serif;
-  font-size: 14px;
-  left: 0;
-  padding-left: 20px;
-}
-
 html[dir=rtl] #fakebox-text {
-  left: auto;
-  right: 13px;
-}
-
-html[dir=rtl] .md #fakebox-text {
   padding-right: 20px;
   right: 0;
 }
@@ -400,23 +360,15 @@
 #fakebox-cursor {
   background: #333;
   bottom: 12px;
-  left: 13px;
+  left: 20px;
   position: absolute;
   top: 12px;
   visibility: hidden;
   width: 1px;
 }
 
-.md #fakebox-cursor {
-  left: 20px;
-}
-
 html[dir=rtl] #fakebox-cursor {
   left: auto;
-  right: 13px;
-}
-
-html[dir=rtl] .md #fakebox-cursor {
   right: 20px;
 }
 
@@ -425,25 +377,18 @@
   background-size: 24px 24px;
   bottom: 0;
   cursor: pointer;
+  margin-right: 12px;
   padding: 22px 12px 0;
   position: absolute;
   right: 0;
   top: 0;
-  width: 41px;
-}
-
-.md #fakebox-microphone {
-  margin-right: 12px;
   width: 28px;
 }
 
 html[dir=rtl] #fakebox-microphone {
   left: 0;
-  right: auto;
-}
-
-html[dir=rtl] .md #fakebox-microphone {
   margin-left: 12px;
+  right: auto;
 }
 
 @keyframes blink {
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index 762ae75..c4744a4 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -111,7 +111,6 @@
   HIDE_NOTIFICATION: 'notice-hide',
   INITED: 'inited',  // Reveals the <body> once init() is done.
   LEFT_ALIGN_ATTRIBUTION: 'left-align-attribution',
-  MATERIAL_DESIGN: 'md',  // Applies Material Design styles to the page
   MATERIAL_DESIGN_ICONS:
       'md-icons',  // Applies Material Design styles to Most Visited.
   // Vertically centers the most visited section for a non-Google provided page.
@@ -939,19 +938,9 @@
 function enableMDIcons() {
   $(IDS.MOST_VISITED).classList.add(CLASSES.MATERIAL_DESIGN_ICONS);
   $(IDS.TILES).classList.add(CLASSES.MATERIAL_DESIGN_ICONS);
-  enableMD();
   addRippleAnimations();
 }
 
-
-/**
- * Enables Material Design styles for all NTP components except Most Visited.
- */
-function enableMD() {
-  document.body.classList.add(CLASSES.MATERIAL_DESIGN);
-}
-
-
 /**
  * Enables ripple animations for elements with CLASSES.RIPPLE. The target
  * element must have position relative or absolute.
@@ -1091,8 +1080,6 @@
   if (configData.isGooglePage) {
     if (configData.isMDIconsEnabled || configData.isCustomLinksEnabled) {
       enableMDIcons();
-    } else if (configData.isMDUIEnabled) {
-      enableMD();
     }
 
     if (configData.isCustomLinksEnabled) {
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.css b/chrome/browser/resources/local_ntp/most_visited_single.css
index ab4cdde..627b21ad 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.css
+++ b/chrome/browser/resources/local_ntp/most_visited_single.css
@@ -53,36 +53,19 @@
 }
 
 #most-visited {
-  margin: 0;
+  margin: 10px 0;
   text-align: -webkit-center;
   user-select: none;
-}
-
-.md #most-visited {
-  margin: 10px 0;
   width: 100%
 }
 
-#mv-tiles,
-.mv-tiles-old {
+#mv-tiles {
+  display: flex;
+  flex-wrap: wrap;
   font-size: 0;
   /* Two rows of tiles of 128px each, and 16px of spacing between the rows.
    * If you change this, also change the corresponding values in
    * local_ntp.css. */
-  height: calc(2*var(--tile-height) + var(--tile-margin));
-  line-height: calc(var(--tile-height) + var(--tile-margin));
-  margin: 4px 0 8px 0;
-  opacity: 0;
-  position: absolute;
-  /* This align correctly for both LTR and RTL */
-  text-align: -webkit-auto;
-  transition: opacity 1s;
-  user-select: none;
-}
-
-.md #mv-tiles {
-  display: flex;
-  flex-wrap: wrap;
   height: auto;
   justify-content: center;
   line-height: normal;
@@ -90,10 +73,15 @@
   /* 5 88px tiles per row. If you change this, also change the corresponding
    * values in local_ntp.css. */
   max-width: calc(var(--md-tile-width) * var(--md-max-tiles-row));
+  opacity: 0;
   position: static;
+  /* This align correctly for both LTR and RTL */
+  text-align: -webkit-auto;
+  transition: opacity 1s;
+  user-select: none;
 }
 
-.md .mv-tiles-old {
+.mv-tiles-old {
   display: none;
 }
 
diff --git a/chrome/browser/resources/local_ntp/most_visited_single.js b/chrome/browser/resources/local_ntp/most_visited_single.js
index 62ca596f..1f15847 100644
--- a/chrome/browser/resources/local_ntp/most_visited_single.js
+++ b/chrome/browser/resources/local_ntp/most_visited_single.js
@@ -43,7 +43,6 @@
 const CLASSES = {
   FAILED_FAVICON: 'failed-favicon',  // Applied when the favicon fails to load.
   // Material Design classes.
-  MATERIAL_DESIGN: 'md',  // Applies Material Design styles to the page.
   MD_EMPTY_TILE: 'md-empty-tile',
   MD_FALLBACK_BACKGROUND: 'md-fallback-background',
   MD_FALLBACK_LETTER: 'md-fallback-letter',
@@ -976,7 +975,6 @@
   // Enable Material Design.
   if (queryArgs['enableMD'] == '1') {
     isMDEnabled = true;
-    document.body.classList.add(CLASSES.MATERIAL_DESIGN);
   }
 
   // Enable custom links.
@@ -997,7 +995,7 @@
     resizeTimeout = window.setTimeout(() => {
       resizeTimeout = null;
       updateTileVisibility();
-    }, RESIZE_TIMEOUT_DURATION);
+    }, RESIZE_TIMEOUT_DELAY);
   };
 
   window.addEventListener('message', handlePostMessage);
diff --git a/chrome/browser/resources/pdf/gesture_detector.js b/chrome/browser/resources/pdf/gesture_detector.js
index 59e9bc41..444f321 100644
--- a/chrome/browser/resources/pdf/gesture_detector.js
+++ b/chrome/browser/resources/pdf/gesture_detector.js
@@ -23,7 +23,7 @@
 
     let boundOnTouch =
         /** @type {function(!Event)} */ (this.onTouch_.bind(this));
-    this.element_.addEventListener('touchmove', boundOnTouch, {passive: false});
+    this.element_.addEventListener('touchmove', boundOnTouch, {passive: true});
     this.element_.addEventListener('touchend', boundOnTouch, {passive: true});
     this.element_.addEventListener(
         'touchcancel', boundOnTouch, {passive: true});
@@ -136,10 +136,6 @@
       return;
     }
 
-    // We must preventDefault two finger touchmoves. By doing so native
-    // pinch-zoom does not interfere with our way of handling the event.
-    event.preventDefault();
-
     let scaleRatio = GestureDetector.pinchScaleRatio_(event, lastEvent);
     let startScaleRatio =
         GestureDetector.pinchScaleRatio_(event, this.pinchStartEvent_);
diff --git a/chrome/browser/resources/pdf/index.css b/chrome/browser/resources/pdf/index.css
index b7c2d18..6b3f217 100644
--- a/chrome/browser/resources/pdf/index.css
+++ b/chrome/browser/resources/pdf/index.css
@@ -23,6 +23,8 @@
 #plugin {
   height: 100%;
   position: fixed;
+  /* The viewer implements a custom pinch zoom. */
+  touch-action: pan-x pan-y;
   width: 100%;
   z-index: 1;
 }
diff --git a/chrome/browser/safe_browsing/browser_feature_extractor.cc b/chrome/browser/safe_browsing/browser_feature_extractor.cc
index 1e4cd5b..6997527 100644
--- a/chrome/browser/safe_browsing/browser_feature_extractor.cc
+++ b/chrome/browser/safe_browsing/browser_feature_extractor.cc
@@ -51,7 +51,7 @@
     scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
     IPUrlMap* ips) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  for (IPUrlMap::iterator it = ips->begin(); it != ips->end();) {
+  for (auto it = ips->begin(); it != ips->end();) {
     if (!database_manager.get() ||
         !database_manager->MatchMalwareIP(it->first)) {
       // it++ here returns a copy of the old iterator and passes it to erase.
@@ -96,8 +96,7 @@
                                 const std::vector<IPUrlInfo>& meta_infos,
                                 ClientMalwareRequest* request) {
   DCHECK(request);
-  for (std::vector<IPUrlInfo>::const_iterator it = meta_infos.begin();
-       it != meta_infos.end(); ++it) {
+  for (auto it = meta_infos.begin(); it != meta_infos.end(); ++it) {
     ClientMalwareRequest::UrlInfo* urlinfo =
         request->add_bad_ip_url_info();
     // We add the information about url on the bad ip.
@@ -347,9 +346,7 @@
   int num_visits_24h_ago = 0;
   int num_visits_typed = 0;
   int num_visits_link = 0;
-  for (history::VisitVector::const_iterator it = visits.begin();
-       it != visits.end();
-       ++it) {
+  for (auto it = visits.begin(); it != visits.end(); ++it) {
     if (!ui::PageTransitionIsMainFrame(it->transition)) {
       continue;
     }
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc
index 937cc20..91ebebc 100644
--- a/chrome/browser/safe_browsing/client_side_detection_host.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -728,7 +728,7 @@
   if (ip.empty() || url.empty())
     return;
 
-  IPUrlMap::iterator it = browse_info_->ips.find(ip);
+  auto it = browse_info_->ips.find(ip);
   if (it == browse_info_->ips.end()) {
     if (browse_info_->ips.size() < kMaxIPsPerBrowse) {
       std::vector<IPUrlInfo> url_infos;
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
index d535dec4..9783bcd 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -401,8 +401,7 @@
   std::string hashed = base::SHA1HashString(std::string(
       net::x509_util::CryptoBufferAsStringPiece(issuer.cert_buffer())));
   std::string issuer_fp = base::HexEncode(hashed.data(), hashed.size());
-  for (std::set<std::string>::iterator it = paths_to_check.begin();
-       it != paths_to_check.end(); ++it) {
+  for (auto it = paths_to_check.begin(); it != paths_to_check.end(); ++it) {
     whitelist_strings->push_back("cert/" + issuer_fp + *it);
   }
 }
diff --git a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
index 41c4825..b6fbe66 100644
--- a/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/preference_validation_delegate.cc
@@ -99,14 +99,13 @@
     incident->set_path(pref_path);
     if (proto_value_state == TPIncident::BYPASS_CLEARED ||
         proto_value_state == TPIncident::BYPASS_CHANGED) {
-      for (std::vector<std::string>::const_iterator scan(
-               external_validation_invalid_keys.begin());
+      for (auto scan(external_validation_invalid_keys.begin());
            scan != external_validation_invalid_keys.end(); ++scan) {
         incident->add_split_key(*scan);
       }
     } else {
-      for (std::vector<std::string>::const_iterator scan(invalid_keys.begin());
-           scan != invalid_keys.end(); ++scan) {
+      for (auto scan(invalid_keys.begin()); scan != invalid_keys.end();
+           ++scan) {
         incident->add_split_key(*scan);
       }
     }
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
index 985b7335..1379f8e7 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page.cc
@@ -165,7 +165,7 @@
   // Check to see if some new notifications of unsafe resources have been
   // received while we were showing the interstitial.
   UnsafeResourceMap* unsafe_resource_map = GetUnsafeResourcesMap();
-  UnsafeResourceMap::iterator iter = unsafe_resource_map->find(web_contents());
+  auto iter = unsafe_resource_map->find(web_contents());
   if (iter != unsafe_resource_map->end() && !iter->second.empty()) {
     // All queued unsafe resources should be for the same page:
     UnsafeResourceList unsafe_resources = iter->second;
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index f22d405..f0ebd2c509 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -152,8 +152,7 @@
 
   if (is_google) {
     AddString(translated_strings.get(), "searchboxPlaceholder",
-              features::IsMDUIEnabled() ? IDS_GOOGLE_SEARCH_BOX_EMPTY_HINT_MD
-                                        : IDS_GOOGLE_SEARCH_BOX_EMPTY_HINT);
+              IDS_GOOGLE_SEARCH_BOX_EMPTY_HINT_MD);
 
     // Custom Backgrounds
     AddString(translated_strings.get(), "customizeBackground",
@@ -505,8 +504,6 @@
                            content::BrowserAccessibilityState::GetInstance()
                                ->IsAccessibleBrowser());
 
-    config_data.SetBoolean("isMDUIEnabled", features::IsMDUIEnabled());
-
     config_data.SetBoolean("isMDIconsEnabled", features::IsMDIconsEnabled());
 
     if (is_google) {
diff --git a/chrome/browser/search/ntp_features.cc b/chrome/browser/search/ntp_features.cc
index 9b4fa88..9667ffe 100644
--- a/chrome/browser/search/ntp_features.cc
+++ b/chrome/browser/search/ntp_features.cc
@@ -11,20 +11,15 @@
 namespace features {
 
 // If enabled, the user will see a configuration UI, and be able to select
-// background images to set on the New Tab Page. Implicitly enables |kNtpIcons|.
+// background images to set on the New Tab Page.
 const base::Feature kNtpBackgrounds{"NewTabPageBackgrounds",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
 // If enabled, the user will see the Most Visited tiles updated with Material
-// Design elements. Implicitly enables |kNtpUIMd|.
+// Design elements.
 const base::Feature kNtpIcons{"NewTabPageIcons",
                               base::FEATURE_DISABLED_BY_DEFAULT};
 
-// If enabled, the user will see the New Tab Page updated with Material Design
-// elements.
-const base::Feature kNtpUIMd{"NewTabPageUIMd",
-                             base::FEATURE_DISABLED_BY_DEFAULT};
-
 bool IsCustomLinksEnabled() {
   return ntp_tiles::IsCustomLinksEnabled();
 }
@@ -41,14 +36,4 @@
          base::FeatureList::IsEnabled(features::kExperimentalUi);
 }
 
-bool IsMDUIEnabled() {
-  return base::FeatureList::IsEnabled(kNtpUIMd) ||
-         // MD UI changes are implicitly enabled if Material Design icons,
-         // custom link, or custom backgrounds are enabled.
-         base::FeatureList::IsEnabled(kNtpIcons) ||
-         base::FeatureList::IsEnabled(kNtpBackgrounds) ||
-         base::FeatureList::IsEnabled(ntp_tiles::kNtpCustomLinks) ||
-         base::FeatureList::IsEnabled(features::kExperimentalUi);
-}
-
 }  // namespace features
diff --git a/chrome/browser/search/ntp_features.h b/chrome/browser/search/ntp_features.h
index cc591db..d6a28ad4 100644
--- a/chrome/browser/search/ntp_features.h
+++ b/chrome/browser/search/ntp_features.h
@@ -14,7 +14,6 @@
 
 extern const base::Feature kNtpBackgrounds;
 extern const base::Feature kNtpIcons;
-extern const base::Feature kNtpUIMd;
 
 // Returns whether New Tab Page custom links are enabled.
 bool IsCustomLinksEnabled();
@@ -25,9 +24,6 @@
 // Returns whether the Material Design UI for Most Visited is enabled.
 bool IsMDIconsEnabled();
 
-// Returns whether the Material Design UI is enabled on the New Tab Page.
-bool IsMDUIEnabled();
-
 }  // namespace features
 
 #endif  // CHROME_BROWSER_SEARCH_NTP_FEATURES_H_
diff --git a/chrome/browser/search_engines/template_url_service_sync_unittest.cc b/chrome/browser/search_engines/template_url_service_sync_unittest.cc
index 28c9388f..bf476586 100644
--- a/chrome/browser/search_engines/template_url_service_sync_unittest.cc
+++ b/chrome/browser/search_engines/template_url_service_sync_unittest.cc
@@ -145,8 +145,7 @@
         syncer::SEARCH_ENGINES);
 
   change_map_.erase(change_map_.begin(), change_map_.end());
-  for (syncer::SyncChangeList::const_iterator iter = change_list.begin();
-      iter != change_list.end(); ++iter)
+  for (auto iter = change_list.begin(); iter != change_list.end(); ++iter)
     change_map_[GetGUID(iter->sync_data())] = *iter;
   return syncer::SyncError();
 }
@@ -333,9 +332,8 @@
   SyncDataMap map1 = TemplateURLService::CreateGUIDToSyncDataMap(data1);
   SyncDataMap map2 = TemplateURLService::CreateGUIDToSyncDataMap(data2);
 
-  for (SyncDataMap::const_iterator iter1 = map1.begin();
-      iter1 != map1.end(); iter1++) {
-    SyncDataMap::iterator iter2 = map2.find(iter1->first);
+  for (auto iter1 = map1.cbegin(); iter1 != map1.cend(); ++iter1) {
+    auto iter2 = map2.find(iter1->first);
     if (iter2 != map2.end()) {
       ASSERT_EQ(GetKeyword(iter1->second), GetKeyword(iter2->second));
       ASSERT_EQ(GetURL(iter1->second), GetURL(iter2->second));
diff --git a/chrome/browser/service_process/service_process_control.cc b/chrome/browser/service_process/service_process_control.cc
index d24e8b78..80e2f23 100644
--- a/chrome/browser/service_process/service_process_control.cc
+++ b/chrome/browser/service_process/service_process_control.cc
@@ -154,7 +154,7 @@
 
 // static
 void ServiceProcessControl::RunAllTasksHelper(TaskList* task_list) {
-  TaskList::iterator index = task_list->begin();
+  auto index = task_list->begin();
   while (index != task_list->end()) {
     std::move(*index).Run();
     index = task_list->erase(index);
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc
index a1427743..cc4bc001 100644
--- a/chrome/browser/sessions/session_restore.cc
+++ b/chrome/browser/sessions/session_restore.cc
@@ -249,8 +249,7 @@
     std::vector<Browser*> browsers;
     std::vector<RestoredTab> created_contents;
     // Create a browser instance to put the restored tabs in.
-    for (std::vector<const sessions::SessionWindow*>::const_iterator i = begin;
-         i != end; ++i) {
+    for (auto i = begin; i != end; ++i) {
       Browser* browser = CreateRestoredBrowser(
           BrowserTypeForWindowType((*i)->type), (*i)->bounds, (*i)->workspace,
           (*i)->show_state, (*i)->app_name);
@@ -879,8 +878,7 @@
 bool SessionRestore::IsRestoring(const Profile* profile) {
   if (active_session_restorers == nullptr)
     return false;
-  for (std::set<SessionRestoreImpl*>::const_iterator it =
-           active_session_restorers->begin();
+  for (auto it = active_session_restorers->begin();
        it != active_session_restorers->end(); ++it) {
     if ((*it)->profile() == profile)
       return true;
@@ -892,8 +890,7 @@
 bool SessionRestore::IsRestoringSynchronously() {
   if (!active_session_restorers)
     return false;
-  for (std::set<SessionRestoreImpl*>::const_iterator it =
-           active_session_restorers->begin();
+  for (auto it = active_session_restorers->begin();
        it != active_session_restorers->end(); ++it) {
     if ((*it)->synchronous())
       return true;
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
index 8b1627bc..0cdcf11 100644
--- a/chrome/browser/sessions/session_service.cc
+++ b/chrome/browser/sessions/session_service.cc
@@ -199,7 +199,7 @@
   if (!ShouldTrackChangesToWindow(window_id))
     return;
 
-  IdToRange::iterator i = tab_to_available_range_.find(tab_id);
+  auto i = tab_to_available_range_.find(tab_id);
   if (i != tab_to_available_range_.end())
     tab_to_available_range_.erase(i);
 
@@ -790,13 +790,13 @@
 }
 
 void SessionService::CommitPendingCloses() {
-  for (PendingTabCloseIDs::iterator i = pending_tab_close_ids_.begin();
+  for (auto i = pending_tab_close_ids_.begin();
        i != pending_tab_close_ids_.end(); ++i) {
     ScheduleCommand(sessions::CreateTabClosedCommand(*i));
   }
   pending_tab_close_ids_.clear();
 
-  for (PendingWindowCloseIDs::iterator i = pending_window_close_ids_.begin();
+  for (auto i = pending_window_close_ids_.begin();
        i != pending_window_close_ids_.end(); ++i) {
     ScheduleCommand(sessions::CreateWindowClosedCommand(*i));
   }
diff --git a/chrome/browser/shell_integration_linux.cc b/chrome/browser/shell_integration_linux.cc
index fd3c266..bfd0f1c 100644
--- a/chrome/browser/shell_integration_linux.cc
+++ b/chrome/browser/shell_integration_linux.cc
@@ -232,8 +232,7 @@
 
   std::string quoted_path = "";
   const base::CommandLine::StringVector& argv = command_line.argv();
-  for (base::CommandLine::StringVector::const_iterator i = argv.begin();
-       i != argv.end(); ++i) {
+  for (auto i = argv.begin(); i != argv.end(); ++i) {
     if (i != argv.begin())
       quoted_path += " ";
     quoted_path += QuoteArgForDesktopFileExec(*i);
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
index dffb2b1..5cb0b7f 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
@@ -199,9 +199,7 @@
   }
 
   // Do not migrate if some accounts are not valid.
-  for (std::map<std::string, std::string>::const_iterator iter =
-           db_tokens.begin();
-       iter != db_tokens.end(); ++iter) {
+  for (auto iter = db_tokens.begin(); iter != db_tokens.end(); ++iter) {
     const std::string& prefixed_account_id = iter->first;
     std::string account_id = RemoveAccountIdPrefix(prefixed_account_id);
     AccountInfo account_info = account_tracker->GetAccountInfo(account_id);
@@ -450,7 +448,7 @@
 
 std::string MutableProfileOAuth2TokenServiceDelegate::GetRefreshToken(
     const std::string& account_id) const {
-  AccountStatusMap::const_iterator iter = refresh_tokens_.find(account_id);
+  auto iter = refresh_tokens_.find(account_id);
   if (iter != refresh_tokens_.end()) {
     const std::string refresh_token = iter->second->refresh_token();
     DCHECK(!refresh_token.empty());
@@ -581,9 +579,7 @@
             << db_tokens.size() << " Credential(s).";
     AccountTrackerService::AccountIdMigrationState migration_state =
         account_tracker_service_->GetMigrationState();
-    for (std::map<std::string, std::string>::const_iterator iter =
-             db_tokens.begin();
-         iter != db_tokens.end(); ++iter) {
+    for (auto iter = db_tokens.begin(); iter != db_tokens.end(); ++iter) {
       std::string prefixed_account_id = iter->first;
       std::string refresh_token = iter->second;
 
diff --git a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
index 0278f11..7f54671d 100644
--- a/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
+++ b/chrome/browser/speech/extension_api/tts_engine_extension_api.cc
@@ -127,8 +127,7 @@
       result_voice.remote = voice.remote;
       result_voice.extension_id = extension->id();
 
-      for (std::set<std::string>::const_iterator iter =
-               voice.event_types.begin();
+      for (auto iter = voice.event_types.begin();
            iter != voice.event_types.end(); ++iter) {
         result_voice.events.insert(TtsEventTypeFromString(*iter));
       }
diff --git a/chrome/browser/speech/extension_api/tts_extension_api.cc b/chrome/browser/speech/extension_api/tts_extension_api.cc
index 5545ba0..5dcdc31 100644
--- a/chrome/browser/speech/extension_api/tts_extension_api.cc
+++ b/chrome/browser/speech/extension_api/tts_extension_api.cc
@@ -325,8 +325,7 @@
       result_voice->SetString(constants::kExtensionIdKey, voice.extension_id);
 
     auto event_types = std::make_unique<base::ListValue>();
-    for (std::set<TtsEventType>::iterator iter = voice.events.begin();
-         iter != voice.events.end(); ++iter) {
+    for (auto iter = voice.events.begin(); iter != voice.events.end(); ++iter) {
       const char* event_name_constant = TtsEventTypeToString(*iter);
       event_types->AppendString(event_name_constant);
     }
diff --git a/chrome/browser/speech/tts_controller_impl.cc b/chrome/browser/speech/tts_controller_impl.cc
index 600ca02..9ec2bdf 100644
--- a/chrome/browser/speech/tts_controller_impl.cc
+++ b/chrome/browser/speech/tts_controller_impl.cc
@@ -518,10 +518,8 @@
     // Next, prefer required event types.
     if (utterance->required_event_types().size() > 0) {
       bool has_all_required_event_types = true;
-      for (std::set<TtsEventType>::const_iterator iter =
-               utterance->required_event_types().begin();
-           iter != utterance->required_event_types().end();
-           ++iter) {
+      for (auto iter = utterance->required_event_types().begin();
+           iter != utterance->required_event_types().end(); ++iter) {
         if (voice.events.find(*iter) == voice.events.end()) {
           has_all_required_event_types = false;
           break;
@@ -624,8 +622,7 @@
   if (!platform_impl_)
     return;
 
-  for (std::set<VoicesChangedDelegate*>::iterator iter =
-           voices_changed_delegates_.begin();
+  for (auto iter = voices_changed_delegates_.begin();
        iter != voices_changed_delegates_.end(); ++iter) {
     (*iter)->OnVoicesChanged();
   }
diff --git a/chrome/browser/speech/tts_linux.cc b/chrome/browser/speech/tts_linux.cc
index b471c90..4a62d51 100644
--- a/chrome/browser/speech/tts_linux.cc
+++ b/chrome/browser/speech/tts_linux.cc
@@ -181,8 +181,7 @@
   float pitch = params.pitch > 3 ? 3 : params.pitch;
   pitch = params.pitch < 0.334 ? 0.334 : pitch;
 
-  std::map<std::string, SPDChromeVoice>::iterator it =
-      all_native_voices_->find(voice.name);
+  auto it = all_native_voices_->find(voice.name);
   if (it != all_native_voices_->end()) {
     libspeechd_loader_.spd_set_output_module(conn_, it->second.module.c_str());
     libspeechd_loader_.spd_set_synthesis_voice(conn_, it->second.name.c_str());
@@ -267,10 +266,8 @@
     }
   }
 
-  for (std::map<std::string, SPDChromeVoice>::iterator it =
-           all_native_voices_->begin();
-       it != all_native_voices_->end();
-       it++) {
+  for (auto it = all_native_voices_->begin(); it != all_native_voices_->end();
+       ++it) {
     out_voices->push_back(VoiceData());
     VoiceData& voice = out_voices->back();
     voice.native = true;
diff --git a/chrome/browser/spellchecker/spelling_service_client_unittest.cc b/chrome/browser/spellchecker/spelling_service_client_unittest.cc
index 193c23ce..bf9827d 100644
--- a/chrome/browser/spellchecker/spelling_service_client_unittest.cc
+++ b/chrome/browser/spellchecker/spelling_service_client_unittest.cc
@@ -61,8 +61,7 @@
                       const std::vector<SpellCheckResult>& results) {
     EXPECT_EQ(success_, success);
     base::string16 text(base::UTF8ToUTF16(sanitized_request_text_));
-    for (std::vector<SpellCheckResult>::const_iterator it = results.begin();
-         it != results.end(); ++it) {
+    for (auto it = results.begin(); it != results.end(); ++it) {
       text.replace(it->location, it->length, it->replacements[0]);
     }
     EXPECT_EQ(corrected_text_, text);
diff --git a/chrome/browser/ssl/ssl_config_service_manager_pref.cc b/chrome/browser/ssl/ssl_config_service_manager_pref.cc
index d92c1c9..001d6aa 100644
--- a/chrome/browser/ssl/ssl_config_service_manager_pref.cc
+++ b/chrome/browser/ssl/ssl_config_service_manager_pref.cc
@@ -41,8 +41,7 @@
   std::vector<std::string> results;
   results.reserve(value->GetSize());
   std::string s;
-  for (base::ListValue::const_iterator it = value->begin(); it != value->end();
-       ++it) {
+  for (auto it = value->begin(); it != value->end(); ++it) {
     if (!it->GetAsString(&s))
       continue;
     results.push_back(s);
@@ -58,8 +57,7 @@
   std::vector<uint16_t> cipher_suites;
   cipher_suites.reserve(cipher_strings.size());
 
-  for (std::vector<std::string>::const_iterator it = cipher_strings.begin();
-       it != cipher_strings.end(); ++it) {
+  for (auto it = cipher_strings.begin(); it != cipher_strings.end(); ++it) {
     uint16_t cipher_suite = 0;
     if (!net::ParseSSLCipherString(*it, &cipher_suite)) {
       LOG(ERROR) << "Ignoring unrecognized or unparsable cipher suite: " << *it;
diff --git a/chrome/browser/status_icons/status_icon_menu_model.cc b/chrome/browser/status_icons/status_icon_menu_model.cc
index 7de4b18..2d46f71 100644
--- a/chrome/browser/status_icons/status_icon_menu_model.cc
+++ b/chrome/browser/status_icons/status_icon_menu_model.cc
@@ -91,21 +91,21 @@
 }
 
 bool StatusIconMenuModel::IsCommandIdChecked(int command_id) const {
-  ItemStateMap::const_iterator iter = item_states_.find(command_id);
+  auto iter = item_states_.find(command_id);
   if (iter != item_states_.end())
     return iter->second.checked;
   return false;
 }
 
 bool StatusIconMenuModel::IsCommandIdEnabled(int command_id) const {
-  ItemStateMap::const_iterator iter = item_states_.find(command_id);
+  auto iter = item_states_.find(command_id);
   if (iter != item_states_.end())
     return iter->second.enabled;
   return true;
 }
 
 bool StatusIconMenuModel::IsCommandIdVisible(int command_id) const {
-  ItemStateMap::const_iterator iter = item_states_.find(command_id);
+  auto iter = item_states_.find(command_id);
   if (iter != item_states_.end())
     return iter->second.visible;
   return true;
@@ -113,7 +113,7 @@
 
 bool StatusIconMenuModel::GetAcceleratorForCommandId(
     int command_id, ui::Accelerator* accelerator) const {
-  ItemStateMap::const_iterator iter = item_states_.find(command_id);
+  auto iter = item_states_.find(command_id);
   if (iter != item_states_.end() &&
       iter->second.accelerator.key_code() != ui::VKEY_UNKNOWN) {
     *accelerator = iter->second.accelerator;
@@ -123,14 +123,14 @@
 }
 
 bool StatusIconMenuModel::IsItemForCommandIdDynamic(int command_id) const {
-  ItemStateMap::const_iterator iter = item_states_.find(command_id);
+  auto iter = item_states_.find(command_id);
   if (iter != item_states_.end())
     return iter->second.is_dynamic;
   return false;
 }
 
 base::string16 StatusIconMenuModel::GetLabelForCommandId(int command_id) const {
-  ItemStateMap::const_iterator iter = item_states_.find(command_id);
+  auto iter = item_states_.find(command_id);
   if (iter != item_states_.end())
     return iter->second.label;
   return base::string16();
@@ -138,7 +138,7 @@
 
 base::string16 StatusIconMenuModel::GetSublabelForCommandId(
     int command_id) const {
-  ItemStateMap::const_iterator iter = item_states_.find(command_id);
+  auto iter = item_states_.find(command_id);
   if (iter != item_states_.end())
     return iter->second.sublabel;
   return base::string16();
@@ -146,7 +146,7 @@
 
 bool StatusIconMenuModel::GetIconForCommandId(int command_id,
                                               gfx::Image* image_skia) const {
-  ItemStateMap::const_iterator iter = item_states_.find(command_id);
+  auto iter = item_states_.find(command_id);
   if (iter != item_states_.end() && !iter->second.icon.IsEmpty()) {
     *image_skia = iter->second.icon;
     return true;
diff --git a/chrome/browser/supervised_user/child_accounts/family_info_fetcher.cc b/chrome/browser/supervised_user/child_accounts/family_info_fetcher.cc
index 64e6e03..4e454455 100644
--- a/chrome/browser/supervised_user/child_accounts/family_info_fetcher.cc
+++ b/chrome/browser/supervised_user/child_accounts/family_info_fetcher.cc
@@ -278,9 +278,7 @@
 // static
 bool FamilyInfoFetcher::ParseMembers(const base::ListValue* list,
                                      std::vector<FamilyMember>* members) {
-  for (base::ListValue::const_iterator it = list->begin();
-       it != list->end();
-       it++) {
+  for (auto it = list->begin(); it != list->end(); ++it) {
     FamilyMember member;
     const base::DictionaryValue* dict = NULL;
     if (!it->GetAsDictionary(&dict) || !ParseMember(dict, &member)) {
diff --git a/chrome/browser/supervised_user/experimental/safe_search_url_reporter.cc b/chrome/browser/supervised_user/experimental/safe_search_url_reporter.cc
index 34dce46..1e6e2da 100644
--- a/chrome/browser/supervised_user/experimental/safe_search_url_reporter.cc
+++ b/chrome/browser/supervised_user/experimental/safe_search_url_reporter.cc
@@ -91,7 +91,7 @@
 void SafeSearchURLReporter::OnGetTokenSuccess(
     const OAuth2TokenService::Request* request,
     const OAuth2AccessTokenConsumer::TokenResponse& token_response) {
-  ReportList::iterator it = reports_.begin();
+  auto it = reports_.begin();
   while (it != reports_.end()) {
     if (request == (*it)->access_token_request.get())
       break;
@@ -158,7 +158,7 @@
 void SafeSearchURLReporter::OnGetTokenFailure(
     const OAuth2TokenService::Request* request,
     const GoogleServiceAuthError& error) {
-  ReportList::iterator it = reports_.begin();
+  auto it = reports_.begin();
   while (it != reports_.end()) {
     if (request == (*it)->access_token_request.get())
       break;
diff --git a/chrome/browser/sync/test/integration/apps_helper.cc b/chrome/browser/sync/test/integration/apps_helper.cc
index c8c1cac3..2a8e5bc 100644
--- a/chrome/browser/sync/test/integration/apps_helper.cc
+++ b/chrome/browser/sync/test/integration/apps_helper.cc
@@ -191,7 +191,7 @@
 }
 
 bool AppsMatchChecker::IsExitConditionSatisfied() {
-  std::vector<Profile*>::iterator it = profiles_.begin();
+  auto it = profiles_.begin();
   Profile* profile0 = *it;
   ++it;
   for (; it != profiles_.end(); ++it) {
diff --git a/chrome/browser/sync/test/integration/extensions_helper.cc b/chrome/browser/sync/test/integration/extensions_helper.cc
index c76c8cb2..7b742a3 100644
--- a/chrome/browser/sync/test/integration/extensions_helper.cc
+++ b/chrome/browser/sync/test/integration/extensions_helper.cc
@@ -157,7 +157,7 @@
 }
 
 bool ExtensionsMatchChecker::IsExitConditionSatisfied() {
-  std::vector<Profile*>::iterator it = profiles_.begin();
+  auto it = profiles_.begin();
   Profile* profile0 = *it;
   ++it;
   for (; it != profiles_.end(); ++it) {
diff --git a/chrome/browser/sync/test/integration/fake_server_invalidation_service.cc b/chrome/browser/sync/test/integration/fake_server_invalidation_service.cc
index 666add04..cc0b6a8f 100644
--- a/chrome/browser/sync/test/integration/fake_server_invalidation_service.cc
+++ b/chrome/browser/sync/test/integration/fake_server_invalidation_service.cc
@@ -70,8 +70,7 @@
   syncer::ObjectIdSet object_ids = syncer::ModelTypeSetToObjectIdSet(
       committed_model_types);
   syncer::ObjectIdInvalidationMap invalidation_map;
-  for (syncer::ObjectIdSet::const_iterator it = object_ids.begin();
-       it != object_ids.end(); ++it) {
+  for (auto it = object_ids.begin(); it != object_ids.end(); ++it) {
     // TODO(pvalenzuela): Create more refined invalidations instead of
     // invalidating all items of a given type.
 
diff --git a/chrome/browser/sync/test/integration/performance/typed_urls_sync_perf_test.cc b/chrome/browser/sync/test/integration/performance/typed_urls_sync_perf_test.cc
index fbbcefd6..a4938fd 100644
--- a/chrome/browser/sync/test/integration/performance/typed_urls_sync_perf_test.cc
+++ b/chrome/browser/sync/test/integration/performance/typed_urls_sync_perf_test.cc
@@ -75,8 +75,7 @@
 void TypedUrlsSyncPerfTest::RemoveURLs(int profile) {
   const history::URLRows& urls = GetTypedUrlsFromClient(profile);
   std::vector<GURL> gurls;
-  for (history::URLRows::const_iterator it = urls.begin(); it != urls.end();
-       ++it) {
+  for (auto it = urls.begin(); it != urls.end(); ++it) {
     gurls.push_back(it->url());
   }
   DeleteUrlsFromHistory(profile, gurls);
diff --git a/chrome/browser/sync/test/integration/preferences_helper.cc b/chrome/browser/sync/test/integration/preferences_helper.cc
index 5c21f98..b8b5deb8 100644
--- a/chrome/browser/sync/test/integration/preferences_helper.cc
+++ b/chrome/browser/sync/test/integration/preferences_helper.cc
@@ -87,9 +87,7 @@
   {
     ListPrefUpdate update(GetPrefs(index), pref_name);
     base::ListValue* list = update.Get();
-    for (base::ListValue::const_iterator it = new_value.begin();
-         it != new_value.end();
-         ++it) {
+    for (auto it = new_value.begin(); it != new_value.end(); ++it) {
       list->Append(it->CreateDeepCopy());
     }
   }
@@ -97,9 +95,7 @@
   if (test()->use_verifier()) {
     ListPrefUpdate update_verifier(GetVerifierPrefs(), pref_name);
     base::ListValue* list_verifier = update_verifier.Get();
-    for (base::ListValue::const_iterator it = new_value.begin();
-         it != new_value.end();
-         ++it) {
+    for (auto it = new_value.begin(); it != new_value.end(); ++it) {
       list_verifier->Append(it->CreateDeepCopy());
     }
   }
diff --git a/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc b/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
index b955680..b0795ae 100644
--- a/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
+++ b/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
@@ -60,14 +60,12 @@
 
   for (syncer::ModelType type : common_types) {
     // Look up the progress markers.  Fail if either one is missing.
-    syncer::ProgressMarkerMap::const_iterator pm_it1 =
-        snap1.download_progress_markers().find(type);
+    auto pm_it1 = snap1.download_progress_markers().find(type);
     if (pm_it1 == snap1.download_progress_markers().end()) {
       return false;
     }
 
-    syncer::ProgressMarkerMap::const_iterator pm_it2 =
-        snap2.download_progress_markers().find(type);
+    auto pm_it2 = snap2.download_progress_markers().find(type);
     if (pm_it2 == snap2.download_progress_markers().end()) {
       return false;
     }
diff --git a/chrome/browser/sync/test/integration/search_engines_helper.cc b/chrome/browser/sync/test/integration/search_engines_helper.cc
index 465e598..239a1d3 100644
--- a/chrome/browser/sync/test/integration/search_engines_helper.cc
+++ b/chrome/browser/sync/test/integration/search_engines_helper.cc
@@ -70,8 +70,7 @@
     return false;
   }
 
-  for (GUIDToTURLMap::iterator it = a_turls.begin();
-       it != a_turls.end(); ++it) {
+  for (auto it = a_turls.begin(); it != a_turls.end(); ++it) {
     if (b_turls.find(it->first) == b_turls.end()) {
       DVLOG(1) << "TURL GUID from a not found in b's TURLs: " << it->first;
       return false;
diff --git a/chrome/browser/sync/test/integration/sessions_helper.cc b/chrome/browser/sync/test/integration/sessions_helper.cc
index c6c659b4..f7173ce 100644
--- a/chrome/browser/sync/test/integration/sessions_helper.cc
+++ b/chrome/browser/sync/test/integration/sessions_helper.cc
@@ -110,8 +110,7 @@
 
 bool OpenMultipleTabs(int index, const std::vector<GURL>& urls) {
   Browser* browser = test()->GetBrowser(index);
-  for (std::vector<GURL>::const_iterator it = urls.begin();
-       it != urls.end(); ++it) {
+  for (auto it = urls.begin(); it != urls.end(); ++it) {
     DVLOG(1) << "Opening tab: " << it->spec() << " using browser " << index
              << ".";
     ShowSingletonTab(browser, *it);
diff --git a/chrome/browser/sync/test/integration/sync_app_helper.cc b/chrome/browser/sync/test/integration/sync_app_helper.cc
index f2cf190a..1e892b63 100644
--- a/chrome/browser/sync/test/integration/sync_app_helper.cc
+++ b/chrome/browser/sync/test/integration/sync_app_helper.cc
@@ -173,8 +173,8 @@
     return false;
   }
 
-  AppStateMap::const_iterator it1 = state_map1.begin();
-  AppStateMap::const_iterator it2 = state_map2.begin();
+  auto it1 = state_map1.begin();
+  auto it2 = state_map2.begin();
   while (it1 != state_map1.end()) {
     if (it1->first != it2->first) {
       DVLOG(2) << "Apps for profile " << profile1->GetDebugName()
diff --git a/chrome/browser/sync/test/integration/sync_extension_helper.cc b/chrome/browser/sync/test/integration/sync_extension_helper.cc
index f500d56..57bbc83 100644
--- a/chrome/browser/sync/test/integration/sync_extension_helper.cc
+++ b/chrome/browser/sync/test/integration/sync_extension_helper.cc
@@ -277,8 +277,8 @@
     return false;
   }
 
-  ExtensionStateMap::const_iterator it1 = state_map1.begin();
-  ExtensionStateMap::const_iterator it2 = state_map2.begin();
+  auto it1 = state_map1.begin();
+  auto it2 = state_map2.begin();
   while (it1 != state_map1.end()) {
     if (it1->first != it2->first) {
       DVLOG(1) << "Extensions for profile " << profile1->GetDebugName()
@@ -412,7 +412,7 @@
     ADD_FAILURE();
     return nullptr;
   }
-  ProfileExtensionNameMap::iterator it = profile_extensions_.find(profile);
+  auto it = profile_extensions_.find(profile);
   if (it == profile_extensions_.end()) {
     ADD_FAILURE();
     return nullptr;
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index b32e000..641bf72 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -79,6 +79,7 @@
 #include "components/sync/protocol/sync.pb.h"
 #include "components/sync/test/fake_server/fake_server_network_resources.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/network_service_instance.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_thread.h"
@@ -182,7 +183,8 @@
   Profile* profile = static_cast<Profile*>(context);
   return std::make_unique<invalidation::ProfileInvalidationProvider>(
       std::make_unique<invalidation::P2PInvalidationService>(
-          profile->GetRequestContext(), notification_target),
+          profile->GetRequestContext(), content::GetNetworkConnectionTracker(),
+          notification_target),
       std::make_unique<invalidation::ProfileIdentityProvider>(
           IdentityManagerFactory::GetForProfile(profile)));
 }
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc
index b604e3f..871bcf1 100644
--- a/chrome/browser/themes/browser_theme_pack.cc
+++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -171,7 +171,7 @@
       (*lookup_table)[idr] = prs_id;
     }
   }
-  std::map<int,int>::iterator it = lookup_table->find(idr);
+  auto it = lookup_table->find(idr);
   return (it == lookup_table->end()) ? -1 : it->second;
 }
 
@@ -657,7 +657,7 @@
   // Make sure the |images_on_file_thread_| has bitmaps for supported
   // scale factors before passing to FILE thread.
   pack->images_on_file_thread_ = pack->images_;
-  for (ImageCache::iterator it = pack->images_on_file_thread_.begin();
+  for (auto it = pack->images_on_file_thread_.begin();
        it != pack->images_on_file_thread_.end(); ++it) {
     gfx::ImageSkia* image_skia =
         const_cast<gfx::ImageSkia*>(it->second.ToImageSkia());
@@ -669,8 +669,7 @@
   // ImageSkiaRep for a scale factor not specified by the theme author.
   // Callers of BrowserThemePack::GetImageNamed() to be able to retrieve
   // ImageSkiaReps for all supported scale factors.
-  for (ImageCache::iterator it = pack->images_.begin();
-       it != pack->images_.end(); ++it) {
+  for (auto it = pack->images_.begin(); it != pack->images_.end(); ++it) {
     const gfx::ImageSkia source_image_skia = it->second.AsImageSkia();
     auto source = std::make_unique<ThemeImageSource>(source_image_skia);
     gfx::ImageSkia image_skia(std::move(source), source_image_skia.size());
@@ -912,7 +911,7 @@
     if (data_pack_.get()) {
       memory = data_pack_->GetStaticMemory(raw_id);
     } else {
-      RawImages::const_iterator it = image_memory_.find(raw_id);
+      auto it = image_memory_.find(raw_id);
       if (it != image_memory_.end()) {
         memory = it->second.get();
       }
@@ -1175,8 +1174,7 @@
 
 void BrowserThemePack::BuildSourceImagesArray(const FilePathMap& file_paths) {
   std::vector<int> ids;
-  for (FilePathMap::const_iterator it = file_paths.begin();
-       it != file_paths.end(); ++it) {
+  for (auto it = file_paths.begin(); it != file_paths.end(); ++it) {
     ids.push_back(it->first);
   }
 
@@ -1192,8 +1190,7 @@
   // http://crbug.com/61838
   base::ThreadRestrictions::ScopedAllowIO allow_io;
 
-  for (FilePathMap::const_iterator it = file_paths.begin();
-       it != file_paths.end(); ++it) {
+  for (auto it = file_paths.begin(); it != file_paths.end(); ++it) {
     int prs_id = it->first;
     // Some images need to go directly into |image_memory_|. No modification is
     // necessary or desirable.
@@ -1211,8 +1208,7 @@
       // process scale factor 100% first because the first image added
       // in image_skia.AddRepresentation() determines the DIP size for
       // all representations.
-      for (ScaleFactorToFileMap::const_iterator s2f = it->second.begin();
-           s2f != it->second.end(); ++s2f) {
+      for (auto s2f = it->second.begin(); s2f != it->second.end(); ++s2f) {
         ui::ScaleFactor scale_factor = s2f->first;
         if ((pass == 0 && scale_factor != ui::SCALE_FACTOR_100P) ||
             (pass == 1 && scale_factor == ui::SCALE_FACTOR_100P)) {
@@ -1255,7 +1251,7 @@
 void BrowserThemePack::CropImages(ImageCache* images) const {
   for (size_t i = 0; i < arraysize(kImagesToCrop); ++i) {
     int prs_id = kImagesToCrop[i].prs_id;
-    ImageCache::iterator it = images->find(prs_id);
+    auto it = images->find(prs_id);
     if (it == images->end())
       continue;
 
@@ -1591,8 +1587,7 @@
 
 void BrowserThemePack::RepackImages(const ImageCache& images,
                                     RawImages* reencoded_images) const {
-  for (ImageCache::const_iterator it = images.begin();
-       it != images.end(); ++it) {
+  for (auto it = images.begin(); it != images.end(); ++it) {
     gfx::ImageSkia image_skia = *it->second.ToImageSkia();
 
     typedef std::vector<gfx::ImageSkiaRep> ImageSkiaReps;
@@ -1600,8 +1595,8 @@
     if (image_reps.empty()) {
       NOTREACHED() << "No image reps for resource " << it->first << ".";
     }
-    for (ImageSkiaReps::iterator rep_it = image_reps.begin();
-         rep_it != image_reps.end(); ++rep_it) {
+    for (auto rep_it = image_reps.begin(); rep_it != image_reps.end();
+         ++rep_it) {
       std::vector<unsigned char> bitmap_data;
       if (!gfx::PNGCodec::EncodeBGRASkBitmap(rep_it->GetBitmap(), false,
                                              &bitmap_data)) {
@@ -1619,16 +1614,14 @@
 
 void BrowserThemePack::MergeImageCaches(
     const ImageCache& source, ImageCache* destination) const {
-  for (ImageCache::const_iterator it = source.begin(); it != source.end();
-       ++it) {
+  for (auto it = source.begin(); it != source.end(); ++it) {
     (*destination)[it->first] = it->second;
   }
 }
 
 void BrowserThemePack::AddRawImagesTo(const RawImages& images,
                                       RawDataForWriting* out) const {
-  for (RawImages::const_iterator it = images.begin(); it != images.end();
-       ++it) {
+  for (auto it = images.begin(); it != images.end(); ++it) {
     (*out)[it->first] = base::StringPiece(
         it->second->front_as<char>(), it->second->size());
   }
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc
index b91e626..c3415b00 100644
--- a/chrome/browser/themes/browser_theme_pack_unittest.cc
+++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -143,8 +143,7 @@
 
 void BrowserThemePackTest::VerifyColorMap(
     const std::map<int, SkColor>& color_map) {
-  for (std::map<int, SkColor>::const_iterator it = color_map.begin();
-       it != color_map.end(); ++it) {
+  for (auto it = color_map.begin(); it != color_map.end(); ++it) {
     SkColor color;
     if (!theme_pack_->GetColor(it->first, &color))
       color = GetDefaultColor(it->first);
diff --git a/chrome/browser/themes/theme_syncable_service.cc b/chrome/browser/themes/theme_syncable_service.cc
index 4390b9b..23321bc 100644
--- a/chrome/browser/themes/theme_syncable_service.cc
+++ b/chrome/browser/themes/theme_syncable_service.cc
@@ -89,9 +89,8 @@
 
   // Find the last SyncData that has theme data and set the current theme from
   // it.
-  for (syncer::SyncDataList::const_reverse_iterator sync_data =
-      initial_sync_data.rbegin(); sync_data != initial_sync_data.rend();
-      ++sync_data) {
+  for (auto sync_data = initial_sync_data.rbegin();
+       sync_data != initial_sync_data.rend(); ++sync_data) {
     if (sync_data->GetSpecifics().has_theme()) {
       if (!current_specifics.use_custom_theme() ||
           sync_data->GetSpecifics().theme().use_custom_theme()) {
@@ -171,9 +170,8 @@
 
   // Set current theme from the theme specifics of the last change of type
   // |ACTION_ADD| or |ACTION_UPDATE|.
-  for (syncer::SyncChangeList::const_reverse_iterator theme_change =
-      change_list.rbegin(); theme_change != change_list.rend();
-      ++theme_change) {
+  for (auto theme_change = change_list.rbegin();
+       theme_change != change_list.rend(); ++theme_change) {
     if (theme_change->sync_data().GetSpecifics().has_theme() &&
         (theme_change->change_type() == syncer::SyncChange::ACTION_ADD ||
             theme_change->change_type() == syncer::SyncChange::ACTION_UPDATE)) {
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
index f4791e8..63a820e 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -28,7 +28,6 @@
 #include "ash/wm/window_util.h"
 #include "chrome/browser/chromeos/accessibility/ax_host_service.h"
 #include "ui/base/ui_base_features.h"
-#include "ui/views/widget/widget_delegate.h"
 #endif
 
 using extensions::AutomationEventRouter;
@@ -238,27 +237,9 @@
 
   // Check for a AX node tree in a remote process (e.g. renderer, mojo app).
   ui::AXTreeID child_ax_tree_id;
-  if (ash::Shell::HasRemoteClient(window)) {
-    // For remote mojo apps, the |window| is a DesktopNativeWidgetAura, so the
-    // parent is the widget and the widget's contents view has the child tree.
-    CHECK(window->parent());
-    views::Widget* widget =
-        views::Widget::GetWidgetForNativeWindow(window->parent());
-    CHECK(widget);
-    ui::AXNodeData node_data;
-    widget->widget_delegate()->GetContentsView()->GetAccessibleNodeData(
-        &node_data);
-    child_ax_tree_id = ui::AXTreeID::FromString(
-        node_data.GetStringAttribute(ax::mojom::StringAttribute::kChildTreeId));
-    DCHECK_NE(child_ax_tree_id, ui::AXTreeIDUnknown());
-    DCHECK_NE(child_ax_tree_id, ui::DesktopAXTreeID());
-  } else {
-    // For normal windows the (optional) child tree is an aura window property.
-    ui::AXTreeID* child_ax_tree_id_ptr =
-        window->GetProperty(ui::kChildAXTreeID);
-    if (child_ax_tree_id_ptr)
-      child_ax_tree_id = *child_ax_tree_id_ptr;
-  }
+  std::string* child_ax_tree_id_ptr = window->GetProperty(ui::kChildAXTreeID);
+  if (child_ax_tree_id_ptr)
+    child_ax_tree_id = ui::AXTreeID::FromString(*child_ax_tree_id_ptr);
 
   // If the window has a child AX tree ID, forward the action to the
   // associated AXHostDelegate or RenderFrameHost.
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
index eefda91..f05a879 100644
--- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
+++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.cc
@@ -15,17 +15,25 @@
 #include "build/build_config.h"
 #include "chrome/browser/ui/autofill/local_card_migration_dialog.h"
 #include "chrome/browser/ui/autofill/local_card_migration_dialog_state.h"
+#include "chrome/browser/ui/browser.h"
 #include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/local_card_migration_manager.h"
 #include "components/autofill/core/browser/payments/payments_service_url.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_prefs.h"
+#include "components/prefs/pref_service.h"
+#include "components/user_prefs/user_prefs.h"
+#include "content/public/browser/browser_context.h"
 
 namespace autofill {
 
 LocalCardMigrationDialogControllerImpl::LocalCardMigrationDialogControllerImpl(
     content::WebContents* web_contents)
-    : web_contents_(web_contents), local_card_migration_dialog_(nullptr) {}
+    : web_contents_(web_contents),
+      local_card_migration_dialog_(nullptr),
+      pref_service_(
+          user_prefs::UserPrefs::Get(web_contents->GetBrowserContext())) {}
 
 LocalCardMigrationDialogControllerImpl::
     ~LocalCardMigrationDialogControllerImpl() {
@@ -92,6 +100,8 @@
       AutofillMetrics::
           LOCAL_CARD_MIGRATION_DIALOG_CLOSED_CANCEL_BUTTON_CLICKED);
 
+  prefs::SetLocalCardMigrationPromptPreviouslyCancelled(pref_service_, true);
+
   start_migrating_cards_callback_.Reset();
 }
 
diff --git a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
index f12ecdc3..cbf6e1d7 100644
--- a/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
+++ b/chrome/browser/ui/autofill/local_card_migration_dialog_controller_impl.h
@@ -57,6 +57,8 @@
 
   LocalCardMigrationDialog* local_card_migration_dialog_;
 
+  PrefService* pref_service_;
+
   LocalCardMigrationDialogState view_state_;
 
   LegalMessageLines legal_message_lines_;
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
index 072a727..a0f25dc 100644
--- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
+++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
@@ -58,12 +58,15 @@
 
 void LookalikeUrlNavigationObserver::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
-  DCHECK(navigation_handle->IsInMainFrame());
+  // Ignore subframe and same document navigations.
+  if (!navigation_handle->IsInMainFrame() ||
+      navigation_handle->IsSameDocument())
+    return;
+
   // If the navigation was not committed, it means either the page was a
   // download or error 204/205, or the navigation never left the previous
   // URL. Basically, this isn't a problem since we stayed at the existing URL.
-  // Also ignore same document navigations.
-  if (!navigation_handle->HasCommitted() || navigation_handle->IsSameDocument())
+  if (!navigation_handle->HasCommitted())
     return;
 
   const GURL url = navigation_handle->GetURL();
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc
index 91d69df..c11a411 100644
--- a/chrome/browser/ui/search/local_ntp_browsertest.cc
+++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -602,7 +602,7 @@
   LocalNTPCustomLinksTest()
       : LocalNTPTest(
             /*enabled_features=*/{features::kUseGoogleLocalNtp,
-                                  features::kNtpUIMd, features::kNtpIcons,
+                                  features::kNtpIcons,
                                   ntp_tiles::kNtpCustomLinks},
             /*disabled_features=*/{}) {}
 
@@ -768,9 +768,9 @@
   LocalNTPNonMDTest()
       : LocalNTPTest(
             /*enabled_features=*/{features::kUseGoogleLocalNtp},
-            /*disabled_features=*/{
-                features::kNtpUIMd, features::kNtpBackgrounds,
-                features::kNtpIcons, ntp_tiles::kNtpCustomLinks}) {}
+            /*disabled_features=*/{features::kNtpBackgrounds,
+                                   features::kNtpIcons,
+                                   ntp_tiles::kNtpCustomLinks}) {}
 };
 
 IN_PROC_BROWSER_TEST_F(LocalNTPNonMDTest, LoadsNonMDIframe) {
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
index 94a4758..052767f 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
+++ b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.cc
@@ -94,7 +94,7 @@
 }
 
 const std::vector<std::string>
-LocalCardMigrationDialogView::GetSelectedCardGuids() {
+LocalCardMigrationDialogView::GetSelectedCardGuids() const {
   std::vector<std::string> selected_cards;
   for (int index = 0; index < card_list_view_->child_count(); ++index) {
     MigratableCardView* card =
@@ -142,7 +142,14 @@
 bool LocalCardMigrationDialogView::IsDialogButtonEnabled(
     ui::DialogButton button) const {
   // The buttons will be disabled when card uploading is in progress.
-  return !migration_pending_;
+  if (migration_pending_)
+    return false;
+
+  // If all checkboxes are unchecked, disable the save button.
+  if (button == ui::DIALOG_BUTTON_OK)
+    return !GetSelectedCardGuids().empty();
+
+  return true;
 }
 
 bool LocalCardMigrationDialogView::Accept() {
@@ -182,6 +189,11 @@
   // dialog.
   if (sender == close_migration_dialog_button_) {
     CloseDialog();
+  } else {
+    // Otherwise it is a checkbox just clicked. Enable/disable the save
+    // button if needed.
+    DCHECK_EQ(sender->GetClassName(), views::Checkbox::kViewClassName);
+    DialogModelChanged();
   }
 }
 
diff --git a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h
index 4919f6f9..8a9e3e6 100644
--- a/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h
+++ b/chrome/browser/ui/views/autofill/local_card_migration_dialog_view.h
@@ -77,7 +77,7 @@
   void SetMigrationIsPending(bool is_pending);
   void ShowCloseButton();
   void UpdateDialogToPendingView();
-  const std::vector<std::string> GetSelectedCardGuids();
+  const std::vector<std::string> GetSelectedCardGuids() const;
 
   LocalCardMigrationDialogController* controller_;
 
diff --git a/chrome/browser/ui/views/frame/OWNERS b/chrome/browser/ui/views/frame/OWNERS
index ceae6b94..a03d7983 100644
--- a/chrome/browser/ui/views/frame/OWNERS
+++ b/chrome/browser/ui/views/frame/OWNERS
@@ -5,6 +5,5 @@
 per-file immersive_mode_controller*=pkotwicz@chromium.org
 per-file *x11*=thomasanderson@chromium.org
 per-file desktop_linux_browser_frame_view*=thomasanderson@chromium.org
-per-file top_controls_slide_controller*=afakhry@chromium.org
 
 # COMPONENT: UI>Browser
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_x11.cc b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_x11.cc
index 9c4008e..764ffcb 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_x11.cc
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_x11.cc
@@ -66,14 +66,6 @@
   DesktopWindowTreeHostX11::CloseNow();
 }
 
-void BrowserDesktopWindowTreeHostX11::OnMaximizedStateChanged() {
-  browser_view_->frame()->GetFrameView()->OnMaximizedStateChanged();
-}
-
-void BrowserDesktopWindowTreeHostX11::OnFullscreenStateChanged() {
-  browser_view_->frame()->GetFrameView()->OnFullscreenStateChanged();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserDesktopWindowTreeHost, public:
 
diff --git a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_x11.h b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_x11.h
index 39731e73..11ab3eff 100644
--- a/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_x11.h
+++ b/chrome/browser/ui/views/frame/browser_desktop_window_tree_host_x11.h
@@ -37,8 +37,6 @@
   // Overridden from views::DesktopWindowTreeHostX11:
   void Init(const views::Widget::InitParams& params) override;
   void CloseNow() override;
-  void OnMaximizedStateChanged() override;
-  void OnFullscreenStateChanged() override;
 
   BrowserView* browser_view_;
 
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index a3648bb..2a3a25d 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -71,8 +71,6 @@
   UpdateMinimumSize();
 }
 
-void BrowserNonClientFrameView::OnMaximizedStateChanged() {}
-
 void BrowserNonClientFrameView::OnFullscreenStateChanged() {}
 
 bool BrowserNonClientFrameView::CaptionButtonsOnLeadingEdge() const {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
index 598a2dff..8a2cf82 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.h
@@ -45,11 +45,7 @@
   // Called when BrowserView creates all it's child views.
   virtual void OnBrowserViewInitViewsComplete();
 
-  // Called on Linux X11 after the browser window is maximized or restored.
-  virtual void OnMaximizedStateChanged();
-
-  // Called on Linux X11 and Mac after the browser window is fullscreened or
-  // unfullscreened.
+  // Called on Mac after the browser window is fullscreened or unfullscreened.
   virtual void OnFullscreenStateChanged();
 
   // Returns whether the caption buttons are drawn at the leading edge (i.e. the
diff --git a/chrome/browser/ui/views/frame/desktop_linux_browser_frame_view.cc b/chrome/browser/ui/views/frame/desktop_linux_browser_frame_view.cc
index 42788ccb..e748671f 100644
--- a/chrome/browser/ui/views/frame/desktop_linux_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/desktop_linux_browser_frame_view.cc
@@ -8,6 +8,12 @@
 #include "chrome/browser/ui/views/nav_button_provider.h"
 #include "ui/views/controls/button/image_button.h"
 
+bool DesktopLinuxBrowserFrameView::DrawFrameButtonParams::operator==(
+    const DrawFrameButtonParams& other) const {
+  return top_area_height == other.top_area_height &&
+         maximized == other.maximized && active == other.active;
+}
+
 DesktopLinuxBrowserFrameView::DesktopLinuxBrowserFrameView(
     BrowserFrame* frame,
     BrowserView* browser_view,
@@ -19,10 +25,24 @@
 
 DesktopLinuxBrowserFrameView::~DesktopLinuxBrowserFrameView() {}
 
-void DesktopLinuxBrowserFrameView::MaybeRedrawFrameButtons() {
-  nav_button_provider_->RedrawImages(
+void DesktopLinuxBrowserFrameView::Layout() {
+  // Calling MaybeUpdateCachedFrameButtonImages() from Layout() is sufficient to
+  // catch all cases that could update the appearance, since
+  // DesktopWindowTreeHostX11::UpdateWindowProperties() does a layout any time
+  // any properties change.
+  MaybeUpdateCachedFrameButtonImages();
+  OpaqueBrowserFrameView::Layout();
+}
+
+void DesktopLinuxBrowserFrameView::MaybeUpdateCachedFrameButtonImages() {
+  DrawFrameButtonParams params{
       GetTopAreaHeight() - layout()->TitlebarTopThickness(!IsMaximized()),
-      IsMaximized(), ShouldPaintAsActive());
+      IsMaximized(), ShouldPaintAsActive()};
+  if (cache_ == params)
+    return;
+  cache_ = params;
+  nav_button_provider_->RedrawImages(params.top_area_height, params.maximized,
+                                     params.active);
   for (auto type : {
            chrome::FrameButtonDisplayType::kMinimize,
            IsMaximized() ? chrome::FrameButtonDisplayType::kRestore
diff --git a/chrome/browser/ui/views/frame/desktop_linux_browser_frame_view.h b/chrome/browser/ui/views/frame/desktop_linux_browser_frame_view.h
index b89977f4..7d710d4 100644
--- a/chrome/browser/ui/views/frame/desktop_linux_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/desktop_linux_browser_frame_view.h
@@ -20,9 +20,21 @@
 
  protected:
   // OpaqueBrowserFrameView:
-  void MaybeRedrawFrameButtons() override;
+  void Layout() override;
 
  private:
+  struct DrawFrameButtonParams {
+    bool operator==(const DrawFrameButtonParams& other) const;
+
+    int top_area_height;
+    bool maximized;
+    bool active;
+  };
+
+  // Redraws the image resources associated with the minimize, maximize,
+  // restore, and close buttons.
+  virtual void MaybeUpdateCachedFrameButtonImages();
+
   // Returns one of |{minimize,maximize,restore,close}_button_|
   // corresponding to |type|.
   views::ImageButton* GetButtonFromDisplayType(
@@ -30,6 +42,8 @@
 
   std::unique_ptr<views::NavButtonProvider> nav_button_provider_;
 
+  DrawFrameButtonParams cache_{0, false, false};
+
   DISALLOW_COPY_AND_ASSIGN(DesktopLinuxBrowserFrameView);
 };
 
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index 1edd5cd3..e9ac8c1 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -191,28 +191,6 @@
 ///////////////////////////////////////////////////////////////////////////////
 // OpaqueBrowserFrameView, BrowserNonClientFrameView implementation:
 
-void OpaqueBrowserFrameView::OnBrowserViewInitViewsComplete() {
-  BrowserNonClientFrameView::OnBrowserViewInitViewsComplete();
-
-  // After views are initialized, we know the top area height for the
-  // first time, so redraw the frame buttons at the appropriate size.
-  MaybeRedrawFrameButtons();
-}
-
-void OpaqueBrowserFrameView::OnMaximizedStateChanged() {
-  BrowserNonClientFrameView::OnMaximizedStateChanged();
-
-  // The top area height can change depending on the maximized state.
-  MaybeRedrawFrameButtons();
-}
-
-void OpaqueBrowserFrameView::OnFullscreenStateChanged() {
-  BrowserNonClientFrameView::OnFullscreenStateChanged();
-
-  // The top area height is 0 when the window is fullscreened.
-  MaybeRedrawFrameButtons();
-}
-
 gfx::Rect OpaqueBrowserFrameView::GetBoundsForTabStrip(
     views::View* tabstrip) const {
   if (!tabstrip)
@@ -357,7 +335,6 @@
   BrowserNonClientFrameView::ActivationChanged(active);
   if (hosted_app_button_container_)
     hosted_app_button_container_->SetPaintAsActive(active);
-  MaybeRedrawFrameButtons();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -377,11 +354,6 @@
   node_data->role = ax::mojom::Role::kTitleBar;
 }
 
-void OpaqueBrowserFrameView::OnNativeThemeChanged(
-    const ui::NativeTheme* native_theme) {
-  MaybeRedrawFrameButtons();
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // OpaqueBrowserFrameView, views::ButtonListener implementation:
 
@@ -574,8 +546,6 @@
          platform_observer_->IsUsingSystemTheme();
 }
 
-void OpaqueBrowserFrameView::MaybeRedrawFrameButtons() {}
-
 ///////////////////////////////////////////////////////////////////////////////
 // OpaqueBrowserFrameView, private:
 
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
index 17adead2..33d9977 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.h
@@ -49,9 +49,6 @@
   ~OpaqueBrowserFrameView() override;
 
   // BrowserNonClientFrameView:
-  void OnBrowserViewInitViewsComplete() override;
-  void OnMaximizedStateChanged() override;
-  void OnFullscreenStateChanged() override;
   gfx::Rect GetBoundsForTabStrip(views::View* tabstrip) const override;
   int GetTopInset(bool restored) const override;
   int GetThemeBackgroundXInset() const override;
@@ -76,7 +73,6 @@
   const char* GetClassName() const override;
   void ChildPreferredSizeChanged(views::View* child) override;
   void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
-  void OnNativeThemeChanged(const ui::NativeTheme* native_theme) override;
 
   // views::ButtonListener:
   void ButtonPressed(views::Button* sender, const ui::Event& event) override;
@@ -127,10 +123,6 @@
 
   OpaqueBrowserFrameViewLayout* layout() { return layout_; }
 
-  // If native window frame buttons are enabled, redraws the image resources
-  // associated with |{minimize,maximize,restore,close}_button_|.
-  virtual void MaybeRedrawFrameButtons();
-
  private:
   friend class HostedAppOpaqueBrowserFrameViewTest;
 
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
index 255f82d..1195a14 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h
@@ -147,6 +147,9 @@
     ALIGN_TRAILING
   };
 
+  // views::LayoutManager:
+  void Layout(views::View* host) override;
+
   bool has_trailing_buttons() const { return has_trailing_buttons_; }
 
   virtual bool ShouldDrawImageMirrored(views::ImageButton* button,
@@ -189,7 +192,6 @@
   void SetView(int id, views::View* view);
 
   // views::LayoutManager:
-  void Layout(views::View* host) override;
   gfx::Size GetPreferredSize(const views::View* host) const override;
   void ViewAdded(views::View* host, views::View* view) override;
   void ViewRemoved(views::View* host, views::View* view) override;
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller.h b/chrome/browser/ui/views/frame/top_controls_slide_controller.h
index e243e65..dfa72ed 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller.h
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller.h
@@ -52,9 +52,6 @@
   // changed state.
   virtual void SetTopControlsGestureScrollInProgress(bool in_progress) = 0;
 
-  // Returns true while gesture scrolls are in progress.
-  virtual bool IsTopControlsGestureScrollInProgress() const = 0;
-
  private:
   DISALLOW_COPY_AND_ASSIGN(TopControlsSlideController);
 };
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
index dfd23d4..c1b0b08 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
@@ -163,9 +163,9 @@
   float shown_ratio() const { return shown_ratio_; }
   bool shrink_renderer_size() const { return shrink_renderer_size_; }
 
-  void SetShownRatio(float ratio, bool sliding_or_scrolling_in_progress) {
+  void SetShownRatio(float ratio, bool sliding_in_progress) {
     shown_ratio_ = ratio;
-    if (!sliding_or_scrolling_in_progress)
+    if (!sliding_in_progress)
       UpdateDoBrowserControlsShrinkRendererSize();
   }
 
@@ -248,8 +248,8 @@
 
   // Indicates whether the renderer's viewport size should be shrunk by the
   // height of the browser's top controls. This value should only be updated at
-  // the end of sliding, and should never change while sliding or scrolling are
-  // in progress. https://crbug.com/885223.
+  // the end of sliding, and should never change while sliding is in progress.
+  // https://crbug.com/885223.
   bool shrink_renderer_size_ = true;
 
   DISALLOW_COPY_AND_ASSIGN(TopControlsSlideTabObserver);
@@ -303,22 +303,7 @@
   // Make sure the value tracked per tab is always updated even when sliding is
   // disabled, so that we're always synchronized with the renderer.
   DCHECK(observed_tabs_.count(contents));
-
-  // Note that there are two small windows of intervals between:
-  // 1- When |is_gesture_scrolling_in_progress_| is set to true (i.e. received
-  //    ET_GESTURE_SCROLL_BEGIN) and when |is_sliding_in_progress_| is set to
-  //    true (i.e. top-chrome actually starts moving), and
-  // 2- When |is_gesture_scrolling_in_progress_| is set to false (i.e.
-  //    ET_GESTURE_SCROLL_END was received) and when |is_sliding_in_progress_|
-  //    is set to false (i.e. top-chrome stopped moving) which can happen as the
-  //    renderer continues to animate top-chrome towards fully-shown or
-  //    fully-hidden after the user had lifted their fingers while the
-  //    shown_ratio is still a fractional value.
-  // Even during those two small windows, the
-  // `DoBrowserControlsShrinkRendererSize` bit should remain unchanged from its
-  // current value until sliding reaches a steady state.
-  observed_tabs_[contents]->SetShownRatio(
-      ratio, is_gesture_scrolling_in_progress_ || is_sliding_in_progress_);
+  observed_tabs_[contents]->SetShownRatio(ratio, is_sliding_in_progress_);
 
   if (!IsEnabled()) {
     // However, if sliding is disabled, we don't update |shown_ratio_|, which is
@@ -384,11 +369,6 @@
   Refresh();
 }
 
-bool TopControlsSlideControllerChromeOS::IsTopControlsGestureScrollInProgress()
-    const {
-  return is_gesture_scrolling_in_progress_;
-}
-
 void TopControlsSlideControllerChromeOS::OnTabletModeToggled(
     bool tablet_mode_enabled) {
   OnEnabledStateChanged(tablet_mode_enabled && !browser_view_->IsFullscreen());
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h
index ff1a1262..0c0b11b 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.h
@@ -51,7 +51,6 @@
   bool DoBrowserControlsShrinkRendererSize(
       const content::WebContents* contents) const override;
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
-  bool IsTopControlsGestureScrollInProgress() const override;
 
   // TabletModeClientObserver:
   void OnTabletModeToggled(bool tablet_mode_enabled) override;
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
index 9cb880a..c104d14 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -54,24 +54,11 @@
                                         const gfx::Point& start_point,
                                         const gfx::Point& end_point) {
   DCHECK(generator);
-  generator->GestureScrollSequenceWithCallback(
+  generator->GestureScrollSequence(
       start_point, end_point,
       generator->CalculateScrollDurationForFlingVelocity(
           start_point, end_point, 100 /* velocity */, 2 /* steps */),
-      2 /* steps */,
-      base::BindRepeating([](ui::EventType, const gfx::Vector2dF&) {
-        // Give the event a chance to propagate to renderer before sending the
-        // next one.
-        base::RunLoop().RunUntilIdle();
-      }));
-}
-
-// Checks that the translation part of the two given transforms are equal.
-void CompareTranslations(const gfx::Transform& t1, const gfx::Transform& t2) {
-  const gfx::Vector2dF t1_translation = t1.To2dTranslation();
-  const gfx::Vector2dF t2_translation = t2.To2dTranslation();
-  EXPECT_FLOAT_EQ(t1_translation.x(), t2_translation.x());
-  EXPECT_FLOAT_EQ(t1_translation.y(), t2_translation.y());
+      2 /* steps */);
 }
 
 // Waits for the first non-empty paint for a given WebContents. To be able to
@@ -100,8 +87,7 @@
   DISALLOW_COPY_AND_ASSIGN(TabNonEmptyPaintWaiter);
 };
 
-// Waits for a given terminal value (1.f or 0.f) of the browser top controls
-// shown ratio on a given browser window.
+// Waits for a given browser top controls shown ratio on a given browser window.
 class TopControlsShownRatioWaiter {
  public:
   explicit TopControlsShownRatioWaiter(
@@ -109,10 +95,6 @@
       : controller_(controller) {}
 
   void WaitForRatio(float ratio) {
-    DCHECK(ratio == 1.f || ratio == 0.f) << "Should only be used to wait for "
-                                            "terminal values of the shown "
-                                            "ratio.";
-
     waiting_for_shown_ratio_ = ratio;
     if (CheckRatio())
       return;
@@ -123,11 +105,7 @@
 
  private:
   bool CheckRatio() {
-    // To avoid flakes, we also check that gesture scrolling is not in progress
-    // which means for a terminal value of the shown ratio (that we're waiting
-    // for) sliding is also not in progress and we reached a steady state.
-    if (!controller_->IsTopControlsGestureScrollInProgress() &&
-        cc::MathUtil::IsWithinEpsilon(controller_->GetShownRatio(),
+    if (cc::MathUtil::IsWithinEpsilon(controller_->GetShownRatio(),
                                       waiting_for_shown_ratio_)) {
       if (run_loop_)
         run_loop_->Quit();
@@ -294,76 +272,15 @@
     }
   }
 
-  // This is used as a callback of type |ScrollStepCallback| of the function
-  // EventGenerator::GestureScrollSequenceWithCallback() that will be called at
-  // the scroll steps of ET_GESTURE_SCROLL_BEGIN, ET_GESTURE_SCROLL_UPDATE, and
-  // ET_GESTURE_SCROLL_END.
-  //
-  // It verifies the state of the browser window when the active page is being
-  // scrolled by touch gestures in such a way that will result in the top
-  // controls shown ratio becoming a fractional value (i.e. sliding top-chrome
-  // is in progress).
-  // The |expected_shrink_renderer_size| will be checked against the
-  // `DoBrowserControlsShrinkRendererSize` bit while sliding.
-  // |out_seen_fractional_shown_ratio| will be set to true if a fractional value
-  // of the shown_ratio has been seen.
-  // |event_type| and |delta| are callback parameters of |ScrollStepCallback|.
-  void CheckIntermediateScrollStep(bool expected_shrink_renderer_size,
-                                   bool* out_seen_fractional_shown_ratio,
-                                   ui::EventType event_type,
-                                   const gfx::Vector2dF& delta) {
-    // Give the event a chance to propagate to renderer before sending the
-    // next one.
-    base::RunLoop().RunUntilIdle();
-
-    if (event_type != ui::ET_GESTURE_SCROLL_UPDATE)
-      return;
-
-    const float shown_ratio = top_controls_slide_controller()->GetShownRatio();
-    if (shown_ratio == 1.f || shown_ratio == 0.f) {
-      // Test only intermediate values.
-      return;
-    }
-
-    *out_seen_fractional_shown_ratio = true;
-
-    const int top_controls_height = browser_view()->GetTopControlsHeight();
-    EXPECT_NE(top_controls_height, 0);
-
-    ui::Layer* root_view_layer =
-        browser_view()->frame()->GetRootView()->layer();
-
-    // While sliding is in progress, the root view paints to a layer.
-    ASSERT_TRUE(root_view_layer);
-
-    // This will be called repeatedly while scrolling is in progress. The
-    // `DoBrowserControlsShrinkRendererSize` bit should remain the same as the
-    // expected value.
-    EXPECT_EQ(expected_shrink_renderer_size,
-              browser_view()->DoBrowserControlsShrinkRendererSize(
-                  browser_view()->GetActiveWebContents()));
-
-    // Check intermediate transforms.
-    gfx::Transform expected_transform;
-    const float y_translation = top_controls_height * (shown_ratio - 1.f);
-    expected_transform.Translate(0, y_translation);
-
-    ASSERT_TRUE(browser_view()
-                    ->contents_web_view()
-                    ->holder()
-                    ->GetNativeViewContainer());
-    ui::Layer* contents_container_layer = browser_view()
-                                              ->contents_web_view()
-                                              ->holder()
-                                              ->GetNativeViewContainer()
-                                              ->layer();
-    ASSERT_TRUE(contents_container_layer);
-    CompareTranslations(expected_transform,
-                        contents_container_layer->transform());
-    CompareTranslations(expected_transform, root_view_layer->transform());
+ private:
+  void CompareTranslations(const gfx::Transform& t1,
+                           const gfx::Transform& t2) const {
+    const gfx::Vector2dF t1_translation = t1.To2dTranslation();
+    const gfx::Vector2dF t2_translation = t2.To2dTranslation();
+    EXPECT_FLOAT_EQ(t1_translation.x(), t2_translation.x());
+    EXPECT_FLOAT_EQ(t1_translation.y(), t2_translation.y());
   }
 
- private:
   base::test::ScopedFeatureList scoped_feature_list_;
 
   DISALLOW_COPY_AND_ASSIGN(TopControlsSlideControllerTest);
@@ -884,73 +801,4 @@
   CheckBrowserLayout(browser_view(), TopChromeShownState::kFullyHidden);
 }
 
-IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest,
-                       TestIntermediateSliding) {
-  ToggleTabletMode();
-  ASSERT_TRUE(GetTabletModeEnabled());
-  EXPECT_TRUE(top_controls_slide_controller()->IsEnabled());
-  EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 1.f);
-
-  // Navigate to our test page that has a long vertical content which we can use
-  // to test page scrolling.
-  OpenUrlAtIndex(embedded_test_server()->GetURL("/top_controls_scroll.html"),
-                 0);
-  EXPECT_TRUE(browser_view()->DoBrowserControlsShrinkRendererSize(
-      browser_view()->GetActiveWebContents()));
-
-  aura::Window* browser_window = browser()->window()->GetNativeWindow();
-  ui::test::EventGenerator event_generator(browser_window->GetRootWindow(),
-                                           browser_window);
-  const gfx::Point start_point = event_generator.current_location();
-  const gfx::Point end_point = start_point + gfx::Vector2d(0, -100);
-
-  // Large number of ET_GESTURE_SCROLL_UPDATE steps that we can see fractional
-  // shown ratios while scrolling is in progress.
-  const int scroll_steps = 1000;
-  const base::TimeDelta scroll_step_delay =
-      event_generator.CalculateScrollDurationForFlingVelocity(
-          start_point, end_point, 1000 /* velocity */, scroll_steps);
-
-  // We need to verify that a fractional value of the shown ratio has been seen,
-  // otherwise the test is useless, since we want to verify the state while
-  // sliding in in progress.
-  bool seen_fractional_shown_ratio = false;
-
-  // We will start scrolling while top-chrome is fully shown, in which case the
-  // `DoBrowserControlsShrinkRendererSize` bit is true. It should remain true
-  // while sliding is in progress.
-  bool expected_shrink_renderer_size = true;
-  event_generator.GestureScrollSequenceWithCallback(
-      start_point, end_point, scroll_step_delay, scroll_steps,
-      base::BindRepeating(
-          &TopControlsSlideControllerTest::CheckIntermediateScrollStep,
-          base::Unretained(this), expected_shrink_renderer_size,
-          &seen_fractional_shown_ratio));
-  EXPECT_TRUE(seen_fractional_shown_ratio);
-  TopControlsShownRatioWaiter waiter(top_controls_slide_controller());
-  waiter.WaitForRatio(0.f);
-  EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 0);
-  CheckBrowserLayout(browser_view(), TopChromeShownState::kFullyHidden);
-
-  // Now that sliding ended, and top-chrome is fully hidden, the
-  // `DoBrowserControlsShrinkRendererSize` bit should be false ...
-  EXPECT_FALSE(browser_view()->DoBrowserControlsShrinkRendererSize(
-      browser_view()->GetActiveWebContents()));
-
-  // ... and when scrolling in the other direction towards a fully shown
-  // top-chrome, it should remain false while sliding is in progress.
-  expected_shrink_renderer_size = false;
-  seen_fractional_shown_ratio = false;
-  event_generator.GestureScrollSequenceWithCallback(
-      end_point, start_point, scroll_step_delay, scroll_steps,
-      base::BindRepeating(
-          &TopControlsSlideControllerTest::CheckIntermediateScrollStep,
-          base::Unretained(this), expected_shrink_renderer_size,
-          &seen_fractional_shown_ratio));
-  EXPECT_TRUE(seen_fractional_shown_ratio);
-  waiter.WaitForRatio(1.f);
-  EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 1.f);
-  CheckBrowserLayout(browser_view(), TopChromeShownState::kFullyShown);
-}
-
 }  // namespace
diff --git a/chrome/browser/ui/views/overlay/close_image_button.cc b/chrome/browser/ui/views/overlay/close_image_button.cc
index c00ea51..cb898b1 100644
--- a/chrome/browser/ui/views/overlay/close_image_button.cc
+++ b/chrome/browser/ui/views/overlay/close_image_button.cc
@@ -8,8 +8,6 @@
 #include "chrome/grit/generated_resources.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/vector_icons.h"
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index e9ff78b..99b01963 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -1537,8 +1537,6 @@
     GetAttachedBrowserWidget()->EndMoveLoop();
   }
 
-  ClearTabDraggingInfo();
-
   if (type != TAB_DESTROYED) {
     // We only finish up the drag if we were actually dragging. If start_drag_
     // is false, the user just clicked and released and didn't move the mouse
@@ -1561,6 +1559,10 @@
       RevertDrag();
   }  // else case the only tab we were dragging was deleted. Nothing to do.
 
+  // Clear tab dragging info after the complete/revert as CompleteDrag() may
+  // need to use some of the properties.
+  ClearTabDraggingInfo();
+
   // Clear out drag data so we don't attempt to do anything with it.
   drag_data_.clear();
 
diff --git a/chrome/browser/ui/views/toolbar/browser_actions_container.cc b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
index 896f0fb..b1f6bbf 100644
--- a/chrome/browser/ui/views/toolbar/browser_actions_container.cc
+++ b/chrome/browser/ui/views/toolbar/browser_actions_container.cc
@@ -89,8 +89,6 @@
 
     if (GetSeparatorAreaWidth() > 0) {
       separator_ = new views::Separator();
-      separator_->SetSize(gfx::Size(views::Separator::kThickness,
-                                    GetLayoutConstant(LOCATION_BAR_ICON_SIZE)));
       AddChildView(separator_);
     }
   }
@@ -450,6 +448,8 @@
     }
   }
   if (separator_) {
+    separator_->SetSize(gfx::Size(views::Separator::kThickness,
+                                  GetLayoutConstant(LOCATION_BAR_ICON_SIZE)));
     if (width() < GetResizeAreaWidth() + GetSeparatorAreaWidth()) {
       separator_->SetVisible(false);
     } else {
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
index 1567c4d..d20d4ac 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_ui.cc
@@ -17,6 +17,7 @@
 #include "chrome/grit/browser_resources.h"
 #include "components/arc/arc_prefs.h"
 #include "components/prefs/pref_service.h"
+#include "content/public/browser/host_zoom_map.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
 
@@ -50,6 +51,12 @@
   source->AddResourcePath("assistant_logo.png", IDR_ASSISTANT_LOGO_PNG);
   source->SetDefaultResource(IDR_ASSISTANT_OPTIN_HTML);
   content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source);
+
+  // Do not zoom for Assistant opt-in web contents.
+  content::HostZoomMap* zoom_map =
+      content::HostZoomMap::GetForWebContents(web_ui->GetWebContents());
+  DCHECK(zoom_map);
+  zoom_map->SetZoomLevelForHost(web_ui->GetWebContents()->GetURL().host(), 0);
 }
 
 AssistantOptInUI::~AssistantOptInUI() = default;
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index f79a4475..2a15989b 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -245,8 +245,6 @@
     "scheduler_delegate.h",
     "service/browser_xr_runtime.cc",
     "service/browser_xr_runtime.h",
-    "service/isolated_device_provider.cc",
-    "service/isolated_device_provider.h",
     "service/vr_service_impl.cc",
     "service/vr_service_impl.h",
     "service/xr_device_impl.cc",
@@ -292,6 +290,24 @@
     "//ui/display",
   ]
 
+  if (is_win) {
+    sources += [
+      "service/isolated_device_provider.cc",
+      "service/isolated_device_provider.h",
+      "win/simple_overlay_renderer_win.cc",
+      "win/simple_overlay_renderer_win.h",
+      "win/vr_browser_renderer_thread_win.cc",
+      "win/vr_browser_renderer_thread_win.h",
+      "win/vr_renderloop_host_win.cc",
+      "win/vr_renderloop_host_win.h",
+    ]
+
+    libs = [
+      "d3d11.lib",
+      "DXGI.lib",
+    ]
+  }
+
   defines = [
     "VR_IMPLEMENTATION",
     "VR_UI_IMPLEMENTATION",
diff --git a/chrome/browser/vr/OWNERS b/chrome/browser/vr/OWNERS
index f6c9ffa..6a785c4 100644
--- a/chrome/browser/vr/OWNERS
+++ b/chrome/browser/vr/OWNERS
@@ -6,6 +6,7 @@
 
 # WebXR-related.
 klausw@chromium.org
+billorr@chromium.org
 
 # Browser Test-related.
 bsheedy@chromium.org
diff --git a/chrome/browser/vr/service/browser_xr_runtime.cc b/chrome/browser/vr/service/browser_xr_runtime.cc
index 386fee22..4813c1d 100644
--- a/chrome/browser/vr/service/browser_xr_runtime.cc
+++ b/chrome/browser/vr/service/browser_xr_runtime.cc
@@ -5,6 +5,8 @@
 #include "chrome/browser/vr/service/browser_xr_runtime.h"
 
 #include "chrome/browser/vr/service/xr_device_impl.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
 #include "device/vr/vr_device.h"
 
 namespace vr {
@@ -45,6 +47,10 @@
   if (immersive_session_controller_) {
     immersive_session_controller_ = nullptr;
     presenting_renderer_device_ = nullptr;
+
+    for (BrowserXRRuntimeObserver& observer : observers_) {
+      observer.SetWebXRWebContents(nullptr);
+    }
   }
 }
 
@@ -120,6 +126,14 @@
     if (options->immersive) {
       presenting_renderer_device_ = device.get();
       immersive_session_controller_ = std::move(immersive_session_controller);
+      immersive_session_controller_.set_connection_error_handler(base::BindOnce(
+          &BrowserXRRuntime::OnImmersiveSessionError, base::Unretained(this)));
+
+      // Notify observers that we have started presentation.
+      content::WebContents* web_contents = device->GetWebContents();
+      for (BrowserXRRuntimeObserver& observer : observers_) {
+        observer.SetWebXRWebContents(web_contents);
+      }
     }
 
     std::move(callback).Run(std::move(session));
@@ -134,6 +148,10 @@
   }
 }
 
+void BrowserXRRuntime::OnImmersiveSessionError() {
+  StopImmersiveSession();
+}
+
 void BrowserXRRuntime::UpdateListeningForActivate(XRDeviceImpl* device) {
   if (device->ListeningForActivate() && device->InFocusedFrame()) {
     bool was_listening = !!listening_for_activation_renderer_device_;
diff --git a/chrome/browser/vr/service/browser_xr_runtime.h b/chrome/browser/vr/service/browser_xr_runtime.h
index 8b69b4f..741f5bf 100644
--- a/chrome/browser/vr/service/browser_xr_runtime.h
+++ b/chrome/browser/vr/service/browser_xr_runtime.h
@@ -5,19 +5,35 @@
 #ifndef CHROME_BROWSER_VR_SERVICE_BROWSER_XR_RUNTIME_H_
 #define CHROME_BROWSER_VR_SERVICE_BROWSER_XR_RUNTIME_H_
 
+#include "base/observer_list.h"
+#include "base/observer_list_types.h"
 #include "device/vr/public/mojom/isolated_xr_service.mojom.h"
 #include "device/vr/public/mojom/vr_service.mojom.h"
 #include "device/vr/vr_device.h"
 #include "mojo/public/cpp/bindings/binding.h"
 
+namespace content {
+class WebContents;
+}
+
 namespace vr {
 
 class XRDeviceImpl;
 
+// This interface is implemented by classes that wish to observer the state of
+// the XR service for a particular runtime.  In particular, observers may
+// currently know when the browser considers a WebContents presenting to an
+// immersive headset.  Implementers of this interface will be called on the main
+// browser thread.  Currently this is used on Windows to drive overlays.
+class BrowserXRRuntimeObserver : public base::CheckedObserver {
+ public:
+  virtual void SetWebXRWebContents(content::WebContents* contents) = 0;
+};
+
 // This class wraps a physical device's interfaces, and registers for events.
-// There is one BrowserXRRuntime per physical device runtime.
-// It manages browser-side handling of state, like which XRDeviceImpl is
-// listening for device activation.
+// There is one BrowserXRRuntime per physical device runtime.  It manages
+// browser-side handling of state, like which XRDeviceImpl is listening for
+// device activation.
 class BrowserXRRuntime : public device::mojom::XRRuntimeEventListener {
  public:
   explicit BrowserXRRuntime(device::mojom::XRRuntimePtr runtime,
@@ -41,6 +57,14 @@
     return display_info_.Clone();
   }
 
+  // Methods called to support metrics/overlays on Windows.
+  void AddObserver(BrowserXRRuntimeObserver* observer) {
+    observers_.AddObserver(observer);
+  }
+  void RemoveObserver(BrowserXRRuntimeObserver* observer) {
+    observers_.RemoveObserver(observer);
+  }
+
  private:
   // device::XRRuntimeEventListener
   void OnDisplayInfoChanged(
@@ -60,6 +84,7 @@
       device::mojom::XRDevice::RequestSessionCallback callback,
       device::mojom::XRSessionPtr session,
       device::mojom::XRSessionControllerPtr immersive_session_controller);
+  void OnImmersiveSessionError();
 
   device::mojom::XRRuntimePtr runtime_;
   device::mojom::XRSessionControllerPtr immersive_session_controller_;
@@ -72,6 +97,8 @@
 
   mojo::Binding<device::mojom::XRRuntimeEventListener> binding_;
 
+  base::ObserverList<BrowserXRRuntimeObserver> observers_;
+
   base::WeakPtrFactory<BrowserXRRuntime> weak_ptr_factory_;
 };
 
diff --git a/chrome/browser/vr/service/isolated_device_provider.cc b/chrome/browser/vr/service/isolated_device_provider.cc
index 47f7943..71434910 100644
--- a/chrome/browser/vr/service/isolated_device_provider.cc
+++ b/chrome/browser/vr/service/isolated_device_provider.cc
@@ -8,6 +8,8 @@
 #include "device/vr/isolated_gamepad_data_fetcher.h"
 #include "services/service_manager/public/cpp/connector.h"
 
+#include "chrome/browser/vr/win/vr_renderloop_host_win.h"
+
 namespace vr {
 
 void IsolatedVRDeviceProvider::Initialize(
@@ -43,33 +45,33 @@
 void IsolatedVRDeviceProvider::OnDeviceAdded(
     device::mojom::XRRuntimePtr device,
     device::mojom::IsolatedXRGamepadProviderFactoryPtr gamepad_factory,
+    device::mojom::XRCompositorHostPtr compositor_host,
     device::mojom::VRDisplayInfoPtr display_info) {
   device::mojom::XRDeviceId id = display_info->id;
-  add_device_callback_.Run(id, std::move(display_info), std::move(device));
-#if BUILDFLAG(ENABLE_OPENVR) || BUILDFLAG(ENABLE_OCULUS_VR)
-  registered_gamepads_.insert(id);
+  add_device_callback_.Run(id, display_info.Clone(), std::move(device));
+  VRBrowserRendererHostWin::AddCompositor(std::move(display_info),
+                                          std::move(compositor_host));
+  registered_devices_.insert(id);
   device::IsolatedGamepadDataFetcher::Factory::AddGamepad(
       id, std::move(gamepad_factory));
-#endif
-  added_devices_.insert(id);
 }
 
 void IsolatedVRDeviceProvider::OnDeviceRemoved(device::mojom::XRDeviceId id) {
   remove_device_callback_.Run(id);
-  added_devices_.erase(id);
-
-#if BUILDFLAG(ENABLE_OPENVR) || BUILDFLAG(ENABLE_OCULUS_VR)
+  registered_devices_.erase(id);
+  VRBrowserRendererHostWin::RemoveCompositor(id);
   device::IsolatedGamepadDataFetcher::Factory::RemoveGamepad(id);
-#endif
 }
 
 void IsolatedVRDeviceProvider::OnServerError() {
   // An error occurred - any devices we have added are now disconnected and
   // should be removed.
-  for (auto id : added_devices_) {
+  for (auto id : registered_devices_) {
     remove_device_callback_.Run(id);
+    VRBrowserRendererHostWin::RemoveCompositor(id);
+    device::IsolatedGamepadDataFetcher::Factory::RemoveGamepad(id);
   }
-  added_devices_.clear();
+  registered_devices_.clear();
 
   // At this point, XRRuntimeManager may be blocked waiting for us to return
   // that we've enumerated all runtimes/devices.  If we lost the connection to
@@ -88,11 +90,10 @@
 IsolatedVRDeviceProvider::IsolatedVRDeviceProvider() : binding_(this) {}
 
 IsolatedVRDeviceProvider::~IsolatedVRDeviceProvider() {
-#if BUILDFLAG(ENABLE_OPENVR) || BUILDFLAG(ENABLE_OCULUS_VR)
-  for (auto gamepad_id : registered_gamepads_) {
-    device::IsolatedGamepadDataFetcher::Factory::RemoveGamepad(gamepad_id);
+  for (auto device_id : registered_devices_) {
+    device::IsolatedGamepadDataFetcher::Factory::RemoveGamepad(device_id);
+    VRBrowserRendererHostWin::RemoveCompositor(device_id);
   }
-#endif
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/service/isolated_device_provider.h b/chrome/browser/vr/service/isolated_device_provider.h
index 5d91bd1c..f7137c1 100644
--- a/chrome/browser/vr/service/isolated_device_provider.h
+++ b/chrome/browser/vr/service/isolated_device_provider.h
@@ -36,6 +36,7 @@
   void OnDeviceAdded(
       device::mojom::XRRuntimePtr device,
       device::mojom::IsolatedXRGamepadProviderFactoryPtr gamepad_factory,
+      device::mojom::XRCompositorHostPtr compositor_host,
       device::mojom::VRDisplayInfoPtr display_info) override;
   void OnDeviceRemoved(device::mojom::XRDeviceId id) override;
   void OnDevicesEnumerated() override;
@@ -51,8 +52,7 @@
   base::RepeatingCallback<void(device::mojom::XRDeviceId)>
       remove_device_callback_;
   base::OnceClosure initialization_complete_;
-  std::set<device::mojom::XRDeviceId> registered_gamepads_;
-  std::set<device::mojom::XRDeviceId> added_devices_;
+  std::set<device::mojom::XRDeviceId> registered_devices_;
   mojo::Binding<device::mojom::IsolatedXRRuntimeProviderClient> binding_;
 };
 
diff --git a/chrome/browser/vr/service/xr_device_impl.cc b/chrome/browser/vr/service/xr_device_impl.cc
index c097e1aca..fea8f982 100644
--- a/chrome/browser/vr/service/xr_device_impl.cc
+++ b/chrome/browser/vr/service/xr_device_impl.cc
@@ -264,6 +264,17 @@
   }
 }
 
+content::WebContents* XRDeviceImpl::GetWebContents() {
+  if (render_frame_host_ != nullptr) {
+    return content::WebContents::FromRenderFrameHost(render_frame_host_);
+  }
+
+  // We should only have a null render_frame_host_ for some unittests, for which
+  // we don't actually expect to get here.
+  NOTREACHED();
+  return nullptr;
+}
+
 bool XRDeviceImpl::IsSecureContextRequirementSatisfied() {
   // We require secure connections unless both the webvr flag and the
   // http flag are enabled.
diff --git a/chrome/browser/vr/service/xr_device_impl.h b/chrome/browser/vr/service/xr_device_impl.h
index 1750a3b..1403e2c 100644
--- a/chrome/browser/vr/service/xr_device_impl.h
+++ b/chrome/browser/vr/service/xr_device_impl.h
@@ -17,6 +17,7 @@
 
 namespace content {
 class RenderFrameHost;
+class WebContents;
 }
 
 namespace device {
@@ -68,6 +69,8 @@
     return weak_ptr_factory_.GetWeakPtr();
   }
 
+  content::WebContents* GetWebContents();
+
  private:
   void ReportRequestPresent();
   bool IsAnotherHostPresenting();
diff --git a/chrome/browser/vr/service/xr_runtime_manager.cc b/chrome/browser/vr/service/xr_runtime_manager.cc
index c720a82c..07a9d36 100644
--- a/chrome/browser/vr/service/xr_runtime_manager.cc
+++ b/chrome/browser/vr/service/xr_runtime_manager.cc
@@ -49,6 +49,11 @@
 XRRuntimeManager* g_xr_runtime_manager = nullptr;
 }  // namespace
 
+XRRuntimeManager::~XRRuntimeManager() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  g_xr_runtime_manager = nullptr;
+}
+
 XRRuntimeManager* XRRuntimeManager::GetInstance() {
   if (!g_xr_runtime_manager) {
     // Register VRDeviceProviders for the current platform
@@ -100,26 +105,38 @@
   return g_xr_runtime_manager;
 }
 
-BrowserXRRuntime* XRRuntimeManager::GetImmersiveRuntime() {
-#if defined(OS_ANDROID)
-  auto* gvr = GetRuntime(device::mojom::XRDeviceId::GVR_DEVICE_ID);
-  if (gvr)
-    return gvr;
-#endif
+bool XRRuntimeManager::HasInstance() {
+  return g_xr_runtime_manager != nullptr;
+}
 
-#if BUILDFLAG(ENABLE_OPENVR)
-  auto* openvr = GetRuntime(device::mojom::XRDeviceId::OPENVR_DEVICE_ID);
-  if (openvr)
-    return openvr;
+void XRRuntimeManager::RecordVrStartupHistograms() {
+#if BUILDFLAG(ENABLE_OPENVR) && !BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
+  device::OpenVRDeviceProvider::RecordRuntimeAvailability();
 #endif
+}
 
-#if BUILDFLAG(ENABLE_OCULUS_VR)
-  auto* oculus = GetRuntime(device::mojom::XRDeviceId::OCULUS_DEVICE_ID);
-  if (oculus)
-    return oculus;
-#endif
+void XRRuntimeManager::AddService(VRServiceImpl* service) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  return nullptr;
+  // Loop through any currently active devices and send Connected messages to
+  // the service. Future devices that come online will send a Connected message
+  // when they are created.
+  InitializeProviders();
+
+  if (AreAllProvidersInitialized())
+    service->InitializationComplete();
+
+  services_.insert(service);
+}
+
+void XRRuntimeManager::RemoveService(VRServiceImpl* service) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  services_.erase(service);
+
+  if (services_.empty()) {
+    // Delete the device manager when it has no active connections.
+    delete g_xr_runtime_manager;
+  }
 }
 
 BrowserXRRuntime* XRRuntimeManager::GetRuntime(device::mojom::XRDeviceId id) {
@@ -152,10 +169,26 @@
   return nullptr;
 }
 
-bool XRRuntimeManager::IsOtherDevicePresenting(XRDeviceImpl* device) {
-  auto* runtime = GetImmersiveRuntime();
-  return runtime && runtime->GetPresentingRendererDevice() &&
-         runtime->GetPresentingRendererDevice() != device;
+BrowserXRRuntime* XRRuntimeManager::GetImmersiveRuntime() {
+#if defined(OS_ANDROID)
+  auto* gvr = GetRuntime(device::mojom::XRDeviceId::GVR_DEVICE_ID);
+  if (gvr)
+    return gvr;
+#endif
+
+#if BUILDFLAG(ENABLE_OPENVR)
+  auto* openvr = GetRuntime(device::mojom::XRDeviceId::OPENVR_DEVICE_ID);
+  if (openvr)
+    return openvr;
+#endif
+
+#if BUILDFLAG(ENABLE_OCULUS_VR)
+  auto* oculus = GetRuntime(device::mojom::XRDeviceId::OCULUS_DEVICE_ID);
+  if (oculus)
+    return oculus;
+#endif
+
+  return nullptr;
 }
 
 device::mojom::VRDisplayInfoPtr XRRuntimeManager::GetCurrentVRDisplayInfo(
@@ -201,6 +234,31 @@
   return device_info;
 }
 
+void XRRuntimeManager::OnRendererDeviceRemoved(XRDeviceImpl* device) {
+  for (const auto& runtime : runtimes_) {
+    runtime.second->OnRendererDeviceRemoved(device);
+  }
+}
+
+bool XRRuntimeManager::IsOtherDevicePresenting(XRDeviceImpl* device) {
+  DCHECK(device);
+
+  auto* runtime = GetImmersiveRuntime();
+  if (!runtime)
+    return false;  // No immersive runtime to be presenting.
+
+  XRDeviceImpl* presenting_device = runtime->GetPresentingRendererDevice();
+  if (!presenting_device)
+    return false;  // No XRDeviceImpl is presenting.
+
+  // True if some other XRDeviceImpl is presenting.
+  return (presenting_device != device);
+}
+
+bool XRRuntimeManager::HasAnyRuntime() {
+  return runtimes_.size() > 0;
+}
+
 void XRRuntimeManager::SupportsSession(
     device::mojom::XRSessionOptionsPtr options,
     device::mojom::XRDevice::SupportsSessionCallback callback) {
@@ -216,14 +274,6 @@
   std::move(callback).Run(true);
 }
 
-bool XRRuntimeManager::HasAnyRuntime() {
-  return runtimes_.size() > 0;
-}
-
-bool XRRuntimeManager::HasInstance() {
-  return g_xr_runtime_manager != nullptr;
-}
-
 XRRuntimeManager::XRRuntimeManager(ProviderList providers)
     : providers_(std::move(providers)) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -231,71 +281,19 @@
   g_xr_runtime_manager = this;
 }
 
-XRRuntimeManager::~XRRuntimeManager() {
+device::mojom::XRRuntime* XRRuntimeManager::GetRuntimeForTest(
+    device::mojom::XRDeviceId id) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  g_xr_runtime_manager = nullptr;
+  DeviceRuntimeMap::iterator iter =
+      runtimes_.find(static_cast<device::mojom::XRDeviceId>(id));
+  if (iter == runtimes_.end())
+    return nullptr;
+
+  return iter->second->GetRuntime();
 }
 
-void XRRuntimeManager::AddService(VRServiceImpl* service) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-
-  // Loop through any currently active devices and send Connected messages to
-  // the service. Future devices that come online will send a Connected message
-  // when they are created.
-  InitializeProviders();
-
-  if (AreAllProvidersInitialized())
-    service->InitializationComplete();
-
-  services_.insert(service);
-}
-
-void XRRuntimeManager::RemoveService(VRServiceImpl* service) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  services_.erase(service);
-
-  if (services_.empty()) {
-    // Delete the device manager when it has no active connections.
-    delete g_xr_runtime_manager;
-  }
-}
-
-void XRRuntimeManager::OnRendererDeviceRemoved(XRDeviceImpl* device) {
-  for (const auto& runtime : runtimes_) {
-    runtime.second->OnRendererDeviceRemoved(device);
-  }
-}
-
-void XRRuntimeManager::AddRuntime(device::mojom::XRDeviceId id,
-                                  device::mojom::VRDisplayInfoPtr info,
-                                  device::mojom::XRRuntimePtr runtime) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  DCHECK(runtimes_.find(id) == runtimes_.end());
-
-  runtimes_[id] =
-      std::make_unique<BrowserXRRuntime>(std::move(runtime), std::move(info));
-  for (VRServiceImpl* service : services_)
-    service->RuntimesChanged();
-}
-
-void XRRuntimeManager::RemoveRuntime(device::mojom::XRDeviceId id) {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  auto it = runtimes_.find(id);
-  DCHECK(it != runtimes_.end());
-
-  // Remove the device from runtimes_ before notifying services that it was
-  // removed, since they will query for devices in RemoveRuntime.
-  std::unique_ptr<BrowserXRRuntime> removed_device = std::move(it->second);
-  runtimes_.erase(it);
-
-  for (VRServiceImpl* service : services_)
-    service->RuntimesChanged();
-}
-
-void XRRuntimeManager::RecordVrStartupHistograms() {
-#if BUILDFLAG(ENABLE_OPENVR) && !BUILDFLAG(ENABLE_ISOLATED_XR_SERVICE)
-  device::OpenVRDeviceProvider::RecordRuntimeAvailability();
-#endif
+size_t XRRuntimeManager::NumberOfConnectedServices() {
+  return services_.size();
 }
 
 void XRRuntimeManager::InitializeProviders() {
@@ -329,22 +327,30 @@
   return num_initialized_providers_ == providers_.size();
 }
 
-size_t XRRuntimeManager::NumberOfConnectedServices() {
-  return services_.size();
+void XRRuntimeManager::AddRuntime(device::mojom::XRDeviceId id,
+                                  device::mojom::VRDisplayInfoPtr info,
+                                  device::mojom::XRRuntimePtr runtime) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  DCHECK(runtimes_.find(id) == runtimes_.end());
+
+  runtimes_[id] =
+      std::make_unique<BrowserXRRuntime>(std::move(runtime), std::move(info));
+  for (VRServiceImpl* service : services_)
+    service->RuntimesChanged();
 }
 
-device::mojom::XRRuntime* XRRuntimeManager::GetRuntimeForTest(unsigned int id) {
+void XRRuntimeManager::RemoveRuntime(device::mojom::XRDeviceId id) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  auto it = runtimes_.find(id);
+  DCHECK(it != runtimes_.end());
 
-  if (id == 0)
-    return nullptr;
+  // Remove the device from runtimes_ before notifying services that it was
+  // removed, since they will query for devices in RemoveRuntime.
+  std::unique_ptr<BrowserXRRuntime> removed_device = std::move(it->second);
+  runtimes_.erase(it);
 
-  DeviceRuntimeMap::iterator iter =
-      runtimes_.find(static_cast<device::mojom::XRDeviceId>(id));
-  if (iter == runtimes_.end())
-    return nullptr;
-
-  return iter->second->GetRuntime();
+  for (VRServiceImpl* service : services_)
+    service->RuntimesChanged();
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/service/xr_runtime_manager.h b/chrome/browser/vr/service/xr_runtime_manager.h
index f16eb55..eca1b7d 100644
--- a/chrome/browser/vr/service/xr_runtime_manager.h
+++ b/chrome/browser/vr/service/xr_runtime_manager.h
@@ -46,6 +46,7 @@
   void AddService(VRServiceImpl* service);
   void RemoveService(VRServiceImpl* service);
 
+  BrowserXRRuntime* GetRuntime(device::mojom::XRDeviceId id);
   BrowserXRRuntime* GetRuntimeForOptions(
       device::mojom::XRSessionOptions* options);
   BrowserXRRuntime* GetImmersiveRuntime();
@@ -70,7 +71,7 @@
 
   // Used by tests to check on device state.
   // TODO: Use XRDeviceId as appropriate.
-  device::mojom::XRRuntime* GetRuntimeForTest(unsigned int id);
+  device::mojom::XRRuntime* GetRuntimeForTest(device::mojom::XRDeviceId id);
 
   size_t NumberOfConnectedServices();
 
@@ -84,8 +85,6 @@
                   device::mojom::XRRuntimePtr runtime);
   void RemoveRuntime(device::mojom::XRDeviceId id);
 
-  BrowserXRRuntime* GetRuntime(device::mojom::XRDeviceId id);
-
   ProviderList providers_;
 
   // VRDevices are owned by their providers, each correspond to a
diff --git a/chrome/browser/vr/service/xr_runtime_manager_unittest.cc b/chrome/browser/vr/service/xr_runtime_manager_unittest.cc
index 82a48c0f..ccba731 100644
--- a/chrome/browser/vr/service/xr_runtime_manager_unittest.cc
+++ b/chrome/browser/vr/service/xr_runtime_manager_unittest.cc
@@ -111,8 +111,8 @@
   EXPECT_TRUE(Provider()->Initialized());
 
   // GetDeviceByIndex should return nullptr if an invalid index in queried.
-  device::mojom::XRRuntime* queried_device =
-      DeviceManager()->GetRuntimeForTest(1);
+  device::mojom::XRRuntime* queried_device = DeviceManager()->GetRuntimeForTest(
+      device::mojom::XRDeviceId::GVR_DEVICE_ID);
   EXPECT_EQ(nullptr, queried_device);
 }
 
diff --git a/chrome/browser/vr/ui.cc b/chrome/browser/vr/ui.cc
index 8f66e5db..f0f21bc 100644
--- a/chrome/browser/vr/ui.cc
+++ b/chrome/browser/vr/ui.cc
@@ -691,7 +691,7 @@
 }
 
 void Ui::HandleMenuButtonEvents(InputEventList* input_event_list) {
-  InputEventList::iterator it = input_event_list->begin();
+  auto it = input_event_list->begin();
   while (it != input_event_list->end()) {
     if (InputEvent::IsMenuButtonEventType((*it)->type())) {
       switch ((*it)->type()) {
diff --git a/chrome/browser/vr/win/simple_overlay_renderer_win.cc b/chrome/browser/vr/win/simple_overlay_renderer_win.cc
new file mode 100644
index 0000000..ffcf1aa
--- /dev/null
+++ b/chrome/browser/vr/win/simple_overlay_renderer_win.cc
@@ -0,0 +1,98 @@
+// 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 <dxgi1_2.h>
+
+#include "chrome/browser/vr/win/simple_overlay_renderer_win.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace vr {
+
+SimpleOverlayRenderer::SimpleOverlayRenderer() {}
+SimpleOverlayRenderer::~SimpleOverlayRenderer() {}
+
+void SimpleOverlayRenderer::Initialize() {
+  D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1};
+  D3D_FEATURE_LEVEL feature_level_out = D3D_FEATURE_LEVEL_11_1;
+  D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, feature_levels,
+                    base::size(feature_levels), D3D11_SDK_VERSION,
+                    device_.GetAddressOf(), &feature_level_out,
+                    context_.GetAddressOf());
+}
+
+void SimpleOverlayRenderer::Render() {
+  if (!device_)
+    return;
+  if (!texture_) {
+    D3D11_TEXTURE2D_DESC desc = {
+        128,
+        128,
+        1,
+        1,
+        DXGI_FORMAT_R8G8B8A8_UNORM,
+        {1, 0},
+        D3D11_USAGE_DEFAULT,
+        D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET,
+        0,
+        D3D11_RESOURCE_MISC_SHARED_NTHANDLE |
+            D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX};
+
+    device_->CreateTexture2D(&desc, nullptr, texture_.GetAddressOf());
+    rtv_ = nullptr;
+  }
+
+  if (texture_ && !rtv_) {
+    D3D11_RENDER_TARGET_VIEW_DESC render_target_view_desc;
+    render_target_view_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+    render_target_view_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+    render_target_view_desc.Texture2D.MipSlice = 0;
+    HRESULT hr = device_->CreateRenderTargetView(
+        texture_.Get(), &render_target_view_desc, rtv_.GetAddressOf());
+    if (FAILED(hr)) {
+      texture_ = nullptr;
+    }
+  }
+
+  if (texture_ && rtv_) {
+    Microsoft::WRL::ComPtr<IDXGIKeyedMutex> mutex;
+    HRESULT hr = texture_.As(&mutex);
+    if (SUCCEEDED(hr)) {
+      mutex->AcquireSync(0, INFINITE);
+
+      static constexpr float color[4] = {1, 0, 0, 0.5};
+      context_->ClearRenderTargetView(rtv_.Get(), color);
+
+      mutex->ReleaseSync(1);
+    } else {
+      rtv_ = nullptr;
+      texture_ = nullptr;
+    }
+  }
+}
+
+mojo::ScopedHandle SimpleOverlayRenderer::GetTexture() {
+  mojo::ScopedHandle handle;
+
+  Microsoft::WRL::ComPtr<IDXGIResource1> dxgi_resource;
+  if (FAILED(texture_.CopyTo(dxgi_resource.GetAddressOf())))
+    return handle;
+
+  HANDLE texture_handle;
+  if (FAILED(dxgi_resource->CreateSharedHandle(
+          nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE,
+          nullptr, &texture_handle)))
+    return handle;
+
+  return mojo::WrapPlatformFile(texture_handle);
+}
+
+gfx::RectF SimpleOverlayRenderer::GetLeft() {
+  return gfx::RectF(0, 0, 0.5, 1);
+}
+
+gfx::RectF SimpleOverlayRenderer::GetRight() {
+  return gfx::RectF(0.5, 0, 0.5, 1);
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/win/simple_overlay_renderer_win.h b/chrome/browser/vr/win/simple_overlay_renderer_win.h
new file mode 100644
index 0000000..5da143b6
--- /dev/null
+++ b/chrome/browser/vr/win/simple_overlay_renderer_win.h
@@ -0,0 +1,42 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VR_WIN_SIMPLE_OVERLAY_RENDERER_WIN_H_
+#define CHROME_BROWSER_VR_WIN_SIMPLE_OVERLAY_RENDERER_WIN_H_
+
+#include <d3d11.h>
+#include <wrl.h>
+
+#include "mojo/public/cpp/system/handle.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace vr {
+
+// This class renders an simple solid-color overlay that can be submitted to
+// be composited on top of WebXR content.  Note that it is not used outside
+// manual testing (requires build changes to enable), and will be replaced with
+// VR-UI overlays rendered through the command buffer.
+class SimpleOverlayRenderer {
+ public:
+  SimpleOverlayRenderer();
+  ~SimpleOverlayRenderer();
+
+  void Initialize();
+  void Render();
+
+  mojo::ScopedHandle GetTexture();
+  gfx::RectF GetLeft();
+  gfx::RectF GetRight();
+
+ private:
+  // DirectX state.
+  Microsoft::WRL::ComPtr<ID3D11DeviceContext> context_;
+  Microsoft::WRL::ComPtr<ID3D11Device> device_;
+  Microsoft::WRL::ComPtr<ID3D11Texture2D> texture_;
+  Microsoft::WRL::ComPtr<ID3D11RenderTargetView> rtv_;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_WIN_SIMPLE_OVERLAY_RENDERER_WIN_H_
diff --git a/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc b/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc
new file mode 100644
index 0000000..98d77e7
--- /dev/null
+++ b/chrome/browser/vr/win/vr_browser_renderer_thread_win.cc
@@ -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.
+
+#include "chrome/browser/vr/win/vr_browser_renderer_thread_win.h"
+
+namespace vr {
+
+VRBrowserRendererThreadWin::VRBrowserRendererThreadWin()
+    : base::Thread("VRBrowserRenderThread") {}
+
+VRBrowserRendererThreadWin::~VRBrowserRendererThreadWin() {
+  Stop();
+}
+
+void VRBrowserRendererThreadWin::StartOverlay(
+    device::mojom::XRCompositorHost* compositor) {
+  device::mojom::ImmersiveOverlayPtrInfo overlay_info;
+  compositor->CreateImmersiveOverlay(mojo::MakeRequest(&overlay_info));
+
+  if (!IsRunning()) {
+    Start();
+  }
+
+  // Post a task to the thread to start an overlay.
+  task_runner()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&VRBrowserRendererThreadWin::StartOverlayOnRenderThread,
+                     base::Unretained(this), std::move(overlay_info)));
+}
+
+void VRBrowserRendererThreadWin::CleanUp() {
+  overlay_ = nullptr;
+}
+
+void VRBrowserRendererThreadWin::StartOverlayOnRenderThread(
+    device::mojom::ImmersiveOverlayPtrInfo overlay) {
+  overlay_.Bind(std::move(overlay));
+
+  renderer_.Initialize();
+  overlay_->SetOverlayAndWebXRVisibility(true, true);
+  overlay_->RequestNextOverlayPose(base::BindOnce(
+      &VRBrowserRendererThreadWin::OnPose, base::Unretained(this)));
+}
+
+void VRBrowserRendererThreadWin::OnPose(device::mojom::XRFrameDataPtr data) {
+  renderer_.Render();
+  overlay_->SubmitOverlayTexture(data->frame_id, renderer_.GetTexture(),
+                                 renderer_.GetLeft(), renderer_.GetRight(),
+                                 base::BindOnce([](bool) {}));
+  overlay_->RequestNextOverlayPose(base::BindOnce(
+      &VRBrowserRendererThreadWin::OnPose, base::Unretained(this)));
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/win/vr_browser_renderer_thread_win.h b/chrome/browser/vr/win/vr_browser_renderer_thread_win.h
new file mode 100644
index 0000000..6e7b6d9
--- /dev/null
+++ b/chrome/browser/vr/win/vr_browser_renderer_thread_win.h
@@ -0,0 +1,41 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VR_WIN_VR_BROWSER_RENDERER_THREAD_WIN_H_
+#define CHROME_BROWSER_VR_WIN_VR_BROWSER_RENDERER_THREAD_WIN_H_
+
+#include "base/threading/thread.h"
+#include "content/public/browser/web_contents.h"
+#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+#include "device/vr/public/mojom/vr_service.mojom.h"
+
+#include "chrome/browser/vr/win/simple_overlay_renderer_win.h"
+
+#include "chrome/browser/vr/service/browser_xr_runtime.h"
+
+namespace vr {
+
+class VRBrowserRendererThreadWin : base::Thread {
+ public:
+  VRBrowserRendererThreadWin();
+  ~VRBrowserRendererThreadWin() override;
+
+  // Initially we are just rendering a solid-color rectangle overlay as a
+  // proof-of-concept.  Eventually, this will draw real content.
+  void StartOverlay(device::mojom::XRCompositorHost* host);
+
+  void CleanUp() override;
+
+ private:
+  void StartOverlayOnRenderThread(
+      device::mojom::ImmersiveOverlayPtrInfo overlay);
+  void OnPose(device::mojom::XRFrameDataPtr data);
+
+  SimpleOverlayRenderer renderer_;
+  device::mojom::ImmersiveOverlayPtr overlay_;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_WIN_VR_BROWSER_RENDERER_THREAD_WIN_H_
diff --git a/chrome/browser/vr/win/vr_renderloop_host_win.cc b/chrome/browser/vr/win/vr_renderloop_host_win.cc
new file mode 100644
index 0000000..f3c3aa5
--- /dev/null
+++ b/chrome/browser/vr/win/vr_renderloop_host_win.cc
@@ -0,0 +1,72 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/vr/win/vr_renderloop_host_win.h"
+#include "chrome/browser/vr/service/browser_xr_runtime.h"
+#include "chrome/browser/vr/service/xr_runtime_manager.h"
+#include "chrome/browser/vr/win/vr_browser_renderer_thread_win.h"
+
+namespace vr {
+
+namespace {
+VRBrowserRendererHostWin* g_vr_renderer_host = nullptr;
+}
+
+VRBrowserRendererHostWin::VRBrowserRendererHostWin(
+    device::mojom::VRDisplayInfoPtr info,
+    device::mojom::XRCompositorHostPtr compositor)
+    : compositor_(std::move(compositor)), info_(std::move(info)) {
+  BrowserXRRuntime* runtime =
+      XRRuntimeManager::GetInstance()->GetRuntime(info_->id);
+  if (runtime) {
+    runtime->AddObserver(this);
+  }
+}
+
+VRBrowserRendererHostWin::~VRBrowserRendererHostWin() {
+  // We don't call BrowserXRRuntime::RemoveObserver, because if we are being
+  // destroyed, it means the corresponding device has been removed from
+  // XRRuntimeManager, and the BrowserXRRuntime has been destroyed.
+}
+
+void VRBrowserRendererHostWin::SetWebXRWebContents(
+    content::WebContents* contents) {
+  // Eventually the contents will be used to poll for permissions, or determine
+  // what overlays should show.
+  if (contents)
+    StartBrowserRenderer();
+  else
+    StopBrowserRenderer();
+}
+
+void VRBrowserRendererHostWin::AddCompositor(
+    device::mojom::VRDisplayInfoPtr info,
+    device::mojom::XRCompositorHostPtr compositor) {
+  // We only expect one device to be enabled at a time.
+  DCHECK(!g_vr_renderer_host);
+  g_vr_renderer_host =
+      new VRBrowserRendererHostWin(std::move(info), std::move(compositor));
+}
+
+void VRBrowserRendererHostWin::RemoveCompositor(device::mojom::XRDeviceId id) {
+  DCHECK(g_vr_renderer_host);
+  g_vr_renderer_host->StopBrowserRenderer();
+  delete g_vr_renderer_host;
+  g_vr_renderer_host = nullptr;
+}
+
+void VRBrowserRendererHostWin::StartBrowserRenderer() {
+// Only used for testing currently.  To see an example overlay, enable the
+// following two lines.
+#if 0
+  render_thread_ = std::make_unique<VRBrowserRendererThreadWin>();
+  render_thread_->StartOverlay(compositor_.get());
+#endif
+}
+
+void VRBrowserRendererHostWin::StopBrowserRenderer() {
+  render_thread_ = nullptr;
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/win/vr_renderloop_host_win.h b/chrome/browser/vr/win/vr_renderloop_host_win.h
new file mode 100644
index 0000000..a3575dce
--- /dev/null
+++ b/chrome/browser/vr/win/vr_renderloop_host_win.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VR_WIN_VR_RENDERLOOP_HOST_WIN_H_
+#define CHROME_BROWSER_VR_WIN_VR_RENDERLOOP_HOST_WIN_H_
+
+#include "base/threading/thread.h"
+#include "chrome/browser/vr/service/browser_xr_runtime.h"
+#include "content/public/browser/web_contents.h"
+#include "device/vr/public/mojom/isolated_xr_service.mojom.h"
+#include "device/vr/public/mojom/vr_service.mojom.h"
+
+namespace vr {
+
+class VRBrowserRendererThreadWin;
+
+class VRBrowserRendererHostWin : public BrowserXRRuntimeObserver {
+ public:
+  // Called by IsolatedDeviceProvider when devices are added/removed.  These
+  // manage the lifetime of VRBrowserRendererHostWin instances.
+  static void AddCompositor(device::mojom::VRDisplayInfoPtr info,
+                            device::mojom::XRCompositorHostPtr compositor);
+  static void RemoveCompositor(device::mojom::XRDeviceId id);
+
+ private:
+  VRBrowserRendererHostWin(device::mojom::VRDisplayInfoPtr info,
+                           device::mojom::XRCompositorHostPtr compositor);
+  ~VRBrowserRendererHostWin() override;
+
+  // Called by BrowserXRRuntime (we register to observe a BrowserXRDevice).
+  // The parameter contents indicate which page is rendering with WebXR or WebVR
+  // presentation.  When null, no page is presenting.
+  void SetWebXRWebContents(content::WebContents* contents) override;
+
+  void StartBrowserRenderer();
+  void StopBrowserRenderer();
+
+  device::mojom::XRCompositorHostPtr compositor_;
+  std::unique_ptr<VRBrowserRendererThreadWin> render_thread_;
+  device::mojom::VRDisplayInfoPtr info_;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_WIN_VR_RENDERLOOP_HOST_WIN_H_
diff --git a/chrome/browser/web_applications/components/web_app_icon_downloader.cc b/chrome/browser/web_applications/components/web_app_icon_downloader.cc
index 9cfd1595..d5b5ed4d 100644
--- a/chrome/browser/web_applications/components/web_app_icon_downloader.cc
+++ b/chrome/browser/web_applications/components/web_app_icon_downloader.cc
@@ -73,9 +73,7 @@
 void WebAppIconDownloader::FetchIcons(
     const std::vector<content::FaviconURL>& favicon_urls) {
   std::vector<GURL> urls;
-  for (std::vector<content::FaviconURL>::const_iterator it =
-           favicon_urls.begin();
-       it != favicon_urls.end(); ++it) {
+  for (auto it = favicon_urls.begin(); it != favicon_urls.end(); ++it) {
     if (it->icon_type != content::FaviconURL::IconType::kInvalid)
       urls.push_back(it->icon_url);
   }
@@ -85,8 +83,7 @@
 void WebAppIconDownloader::FetchIcons(const std::vector<GURL>& urls) {
   // Download icons; put their download ids into |in_progress_requests_| and
   // their urls into |processed_urls_|.
-  for (std::vector<GURL>::const_iterator it = urls.begin();
-       it != urls.end(); ++it) {
+  for (auto it = urls.begin(); it != urls.end(); ++it) {
     // Only start the download if the url hasn't been processed before.
     if (processed_urls_.insert(*it).second)
       in_progress_requests_.insert(DownloadImage(*it));
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.cc b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
index 0f6fd2c..ddb3450a 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.cc
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.cc
@@ -329,3 +329,15 @@
       delay);
   authenticator->dispatched = true;
 }
+
+void AuthenticatorRequestDialogModel::UpdateAuthenticatorReferenceId(
+    base::StringPiece old_authenticator_id,
+    std::string new_authenticator_id) {
+  auto it = std::find_if(
+      saved_authenticators_.begin(), saved_authenticators_.end(),
+      [old_authenticator_id](const auto& authenticator) {
+        return authenticator.authenticator_id == old_authenticator_id;
+      });
+  if (it != saved_authenticators_.end())
+    it->authenticator_id = std::move(new_authenticator_id);
+}
diff --git a/chrome/browser/webauthn/authenticator_request_dialog_model.h b/chrome/browser/webauthn/authenticator_request_dialog_model.h
index 70e42e9..2ff88a9e 100644
--- a/chrome/browser/webauthn/authenticator_request_dialog_model.h
+++ b/chrome/browser/webauthn/authenticator_request_dialog_model.h
@@ -258,6 +258,9 @@
   void SetBluetoothAdapterPowerOnCallback(
       base::RepeatingClosure bluetooth_adapter_power_on_callback);
 
+  void UpdateAuthenticatorReferenceId(base::StringPiece old_authenticator_id,
+                                      std::string new_authenticator_id);
+
   std::vector<AuthenticatorReference>& saved_authenticators() {
     return saved_authenticators_;
   }
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index 859a37a..900e316 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -319,6 +319,16 @@
   });
 }
 
+void ChromeAuthenticatorRequestDelegate::FidoAuthenticatorIdChanged(
+    base::StringPiece old_authenticator_id,
+    std::string new_authenticator_id) {
+  if (!weak_dialog_model_)
+    return;
+
+  weak_dialog_model_->UpdateAuthenticatorReferenceId(
+      old_authenticator_id, std::move(new_authenticator_id));
+}
+
 void ChromeAuthenticatorRequestDelegate::BluetoothAdapterPowerChanged(
     bool is_powered_on) {
   if (!weak_dialog_model_)
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
index 46b4100..2005e988 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.h
@@ -86,6 +86,8 @@
   void FidoAuthenticatorAdded(
       const device::FidoAuthenticator& authenticator) override;
   void FidoAuthenticatorRemoved(base::StringPiece authenticator_id) override;
+  void FidoAuthenticatorIdChanged(base::StringPiece old_authenticator_id,
+                                  std::string new_authenticator_id) override;
   void BluetoothAdapterPowerChanged(bool is_powered_on) override;
 
   // AuthenticatorRequestDialogModel::Observer:
diff --git a/chrome/common/available_offline_content.mojom b/chrome/common/available_offline_content.mojom
index d3e0d53..9c27590 100644
--- a/chrome/common/available_offline_content.mojom
+++ b/chrome/common/available_offline_content.mojom
@@ -7,8 +7,11 @@
 import "url/mojom/url.mojom";
 
 // Categorizes suggested content for metrics reporting.
-// This enum is backed by a UMA histogram therefore its entries should not be
-// deleted or re-ordered and new ones should only be appended.
+// This enum duplicates the values from the NetErrorOfflineSuggestionType
+// metrics enum in enums.xml therefore its entries should not be deleted
+// or re-ordered and new ones should only be appended. Furthermore, changes
+// to this enum might effect the presentation logic in
+// components/neterror/resources/neterror.js.
 enum AvailableContentType {
   // The offline page is prefetched suggested content.
   kPrefetchedUnopenedPage = 0,
diff --git a/chrome/common/mac/app_shim.mojom b/chrome/common/mac/app_shim.mojom
index 7005ff32..3cba641 100644
--- a/chrome/common/mac/app_shim.mojom
+++ b/chrome/common/mac/app_shim.mojom
@@ -25,7 +25,7 @@
   // Create the interface through which BridgedNativeWidget instances may be
   // created (for views::Widgets whose NSWindows exist in the app shim process).
   CreateViewsBridgeFactory(
-      views_bridge_mac.mojom.BridgeFactory& views_bridge_factory);
+      associated views_bridge_mac.mojom.BridgeFactory& views_bridge_factory);
 
   // Create the interface through which a content structure
   // (RenderWidgetHostView or WebContentsView) may create an NSView that exists
diff --git a/chrome/service/BUILD.gn b/chrome/service/BUILD.gn
index 593e8761..9745733 100644
--- a/chrome/service/BUILD.gn
+++ b/chrome/service/BUILD.gn
@@ -41,6 +41,8 @@
     "cloud_print/printer_job_handler.h",
     "cloud_print/printer_job_queue_handler.cc",
     "cloud_print/printer_job_queue_handler.h",
+    "net/in_process_network_connection_tracker.cc",
+    "net/in_process_network_connection_tracker.h",
     "net/service_url_request_context_getter.cc",
     "net/service_url_request_context_getter.h",
     "service_ipc_server.cc",
@@ -70,6 +72,7 @@
     "//mojo/public/cpp/system",
     "//net",
     "//printing",
+    "//services/network/public/cpp",
     "//skia",
     "//third_party/webrtc_overrides",
   ]
diff --git a/chrome/service/DEPS b/chrome/service/DEPS
index 24503a2..305a137 100644
--- a/chrome/service/DEPS
+++ b/chrome/service/DEPS
@@ -8,5 +8,6 @@
   "+components/prefs",
   "+components/version_info",
   "+mojo/core/embedder",
+  "+services/network/public/cpp",
   "+sandbox/win/src",
 ]
diff --git a/chrome/service/cloud_print/cloud_print_proxy.cc b/chrome/service/cloud_print/cloud_print_proxy.cc
index 8d9db0c..0636b6b 100644
--- a/chrome/service/cloud_print/cloud_print_proxy.cc
+++ b/chrome/service/cloud_print/cloud_print_proxy.cc
@@ -26,22 +26,22 @@
 
 namespace cloud_print {
 
-CloudPrintProxy::CloudPrintProxy()
-    : service_prefs_(NULL),
-      client_(NULL),
-      enabled_(false) {
-}
+CloudPrintProxy::CloudPrintProxy() = default;
 
 CloudPrintProxy::~CloudPrintProxy() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   ShutdownBackend();
 }
 
-void CloudPrintProxy::Initialize(ServiceProcessPrefs* service_prefs,
-                                 Client* client) {
+void CloudPrintProxy::Initialize(
+    ServiceProcessPrefs* service_prefs,
+    Client* client,
+    network::NetworkConnectionTracker* network_connection_tracker) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(network_connection_tracker);
   service_prefs_ = service_prefs;
   client_ = client;
+  network_connection_tracker_ = network_connection_tracker;
 }
 
 void CloudPrintProxy::EnableForUser() {
@@ -120,8 +120,9 @@
   oauth_client_info.client_secret =
     google_apis::GetOAuth2ClientSecret(google_apis::CLIENT_CLOUD_PRINT);
   oauth_client_info.redirect_uri = "oob";
-  backend_.reset(new CloudPrintProxyBackend(
-      this, settings, oauth_client_info, enable_job_poll));
+  backend_ = std::make_unique<CloudPrintProxyBackend>(
+      this, settings, oauth_client_info, enable_job_poll,
+      network_connection_tracker_);
   return true;
 }
 
diff --git a/chrome/service/cloud_print/cloud_print_proxy.h b/chrome/service/cloud_print/cloud_print_proxy.h
index 00ef6f3..150d2811 100644
--- a/chrome/service/cloud_print/cloud_print_proxy.h
+++ b/chrome/service/cloud_print/cloud_print_proxy.h
@@ -18,6 +18,10 @@
 
 class ServiceProcessPrefs;
 
+namespace network {
+class NetworkConnectionTracker;
+}
+
 namespace cloud_print {
 
 struct CloudPrintProxyInfo;
@@ -44,7 +48,10 @@
 
   // Initializes the object. This should be called every time an object of this
   // class is constructed.
-  void Initialize(ServiceProcessPrefs* service_prefs, Client* client);
+  void Initialize(
+      ServiceProcessPrefs* service_prefs,
+      Client* client,
+      network::NetworkConnectionTracker* network_connection_tracker);
 
   // Enables/disables cloud printing for the user
   void EnableForUser();
@@ -85,16 +92,18 @@
   std::unique_ptr<CloudPrintProxyBackend> backend_;
   // This class does not own this. It is guaranteed to remain valid for the
   // lifetime of this class.
-  ServiceProcessPrefs* service_prefs_;
+  ServiceProcessPrefs* service_prefs_ = nullptr;
   // This class does not own this. If non-NULL, It is guaranteed to remain
   // valid for the lifetime of this class.
-  Client* client_;
+  Client* client_ = nullptr;
+  // Used to listen for network connection changes.
+  network::NetworkConnectionTracker* network_connection_tracker_ = nullptr;
   // The email address of the account used to authenticate to the Cloud Print
   // service.
   std::string user_email_;
   // This is set to true when the Cloud Print proxy is enabled and after
   // successful authentication with the Cloud Print service.
-  bool enabled_;
+  bool enabled_ = false;
   // This is a cleanup class for unregistering printers on proxy disable.
   std::unique_ptr<CloudPrintWipeout> wipeout_;
 
diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.cc b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
index d2d5729..bdfa18ae 100644
--- a/chrome/service/cloud_print/cloud_print_proxy_backend.cc
+++ b/chrome/service/cloud_print/cloud_print_proxy_backend.cc
@@ -81,7 +81,8 @@
   Core(CloudPrintProxyBackend* backend,
        const ConnectorSettings& settings,
        const gaia::OAuthClientInfo& oauth_client_info,
-       bool enable_job_poll);
+       bool enable_job_poll,
+       network::NetworkConnectionTracker* network_connection_tracker);
 
   // Note:
   //
@@ -168,6 +169,9 @@
   // Our parent CloudPrintProxyBackend
   CloudPrintProxyBackend* const backend_;
 
+  // Monitors for network connection changes.
+  network::NetworkConnectionTracker* const network_connection_tracker_;
+
   // Provides access to networking APIs for auth_.
   std::unique_ptr<network::TransitionalURLLoaderFactoryOwner>
       url_loader_factory_owner_;
@@ -207,12 +211,14 @@
     CloudPrintProxyFrontend* frontend,
     const ConnectorSettings& settings,
     const gaia::OAuthClientInfo& oauth_client_info,
-    bool enable_job_poll)
+    bool enable_job_poll,
+    network::NetworkConnectionTracker* network_connection_tracker)
     : core_thread_("Chrome_CloudPrintProxyCoreThread"),
       frontend_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       frontend_(frontend) {
   DCHECK(frontend_);
-  core_ = new Core(this, settings, oauth_client_info, enable_job_poll);
+  core_ = new Core(this, settings, oauth_client_info, enable_job_poll,
+                   network_connection_tracker);
 }
 
 CloudPrintProxyBackend::~CloudPrintProxyBackend() { DCHECK(!core_.get()); }
@@ -273,8 +279,10 @@
     CloudPrintProxyBackend* backend,
     const ConnectorSettings& settings,
     const gaia::OAuthClientInfo& oauth_client_info,
-    bool enable_job_poll)
+    bool enable_job_poll,
+    network::NetworkConnectionTracker* network_connection_tracker)
     : backend_(backend),
+      network_connection_tracker_(network_connection_tracker),
       oauth_client_info_(oauth_client_info),
       notifications_enabled_(false),
       job_poll_scheduled_(false),
@@ -431,6 +439,7 @@
   notifier_options.xmpp_host_port = net::HostPortPair::FromString(
       base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
           switches::kCloudPrintXmppEndpoint));
+  notifier_options.network_connection_tracker = network_connection_tracker_;
   push_client_ = notifier::PushClient::CreateDefault(notifier_options);
   push_client_->AddObserver(this);
   notifier::Subscription subscription;
diff --git a/chrome/service/cloud_print/cloud_print_proxy_backend.h b/chrome/service/cloud_print/cloud_print_proxy_backend.h
index 2f54c6e..845d5b65 100644
--- a/chrome/service/cloud_print/cloud_print_proxy_backend.h
+++ b/chrome/service/cloud_print/cloud_print_proxy_backend.h
@@ -19,6 +19,10 @@
 struct OAuthClientInfo;
 }
 
+namespace network {
+class NetworkConnectionTracker;
+}
+
 namespace cloud_print {
 
 // CloudPrintProxyFrontend is the interface used by CloudPrintProxyBackend to
@@ -56,10 +60,12 @@
 
 class CloudPrintProxyBackend {
  public:
-  CloudPrintProxyBackend(CloudPrintProxyFrontend* frontend,
-                         const ConnectorSettings& settings,
-                         const gaia::OAuthClientInfo& oauth_client_info,
-                         bool enable_job_poll);
+  CloudPrintProxyBackend(
+      CloudPrintProxyFrontend* frontend,
+      const ConnectorSettings& settings,
+      const gaia::OAuthClientInfo& oauth_client_info,
+      bool enable_job_poll,
+      network::NetworkConnectionTracker* network_connection_tracker);
   ~CloudPrintProxyBackend();
 
   // Legacy mechanism when we have saved user credentials but no saved robot
diff --git a/chrome/service/net/in_process_network_connection_tracker.cc b/chrome/service/net/in_process_network_connection_tracker.cc
new file mode 100644
index 0000000..4c673d9
--- /dev/null
+++ b/chrome/service/net/in_process_network_connection_tracker.cc
@@ -0,0 +1,21 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/service/net/in_process_network_connection_tracker.h"
+
+InProcessNetworkConnectionTracker::InProcessNetworkConnectionTracker() {
+  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+  OnInitialConnectionType(network::mojom::ConnectionType(
+      net::NetworkChangeNotifier::GetConnectionType()));
+}
+
+InProcessNetworkConnectionTracker::~InProcessNetworkConnectionTracker() {
+  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+}
+
+void InProcessNetworkConnectionTracker::OnNetworkChanged(
+    net::NetworkChangeNotifier::ConnectionType type) {
+  network::NetworkConnectionTracker::OnNetworkChanged(
+      network::mojom::ConnectionType(type));
+}
diff --git a/chrome/service/net/in_process_network_connection_tracker.h b/chrome/service/net/in_process_network_connection_tracker.h
new file mode 100644
index 0000000..0cff4ca
--- /dev/null
+++ b/chrome/service/net/in_process_network_connection_tracker.h
@@ -0,0 +1,36 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_SERVICE_NET_IN_PROCESS_NETWORK_CONNECTION_TRACKER_H_
+#define CHROME_SERVICE_NET_IN_PROCESS_NETWORK_CONNECTION_TRACKER_H_
+
+#include "base/macros.h"
+#include "net/base/network_change_notifier.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
+
+// A NetworkConnectionTracker subclass that directly wraps the
+// NetworkChangeNotifier instead of getting connection notifications via
+// the NetworkChangeManager mojo service.
+//
+// This is needed because some dependencies need a NetworkConnectionTracker, but
+// we can't start up the network service within the Cloud Print service process.
+class InProcessNetworkConnectionTracker
+    : public network::NetworkConnectionTracker,
+      private net::NetworkChangeNotifier::NetworkChangeObserver {
+ public:
+  InProcessNetworkConnectionTracker();
+  ~InProcessNetworkConnectionTracker() override;
+
+ protected:
+  using network::NetworkConnectionTracker::OnNetworkChanged;
+
+ private:
+  // net::NetworkChangeNotifier::NetworkChangeObserver implementation:
+  void OnNetworkChanged(
+      net::NetworkChangeNotifier::ConnectionType type) override;
+
+  DISALLOW_COPY_AND_ASSIGN(InProcessNetworkConnectionTracker);
+};
+
+#endif  // CHROME_SERVICE_NET_IN_PROCESS_NETWORK_CONNECTION_TRACKER_H_
diff --git a/chrome/service/net/in_process_network_connection_tracker_unittest.cc b/chrome/service/net/in_process_network_connection_tracker_unittest.cc
new file mode 100644
index 0000000..ff5dfb6
--- /dev/null
+++ b/chrome/service/net/in_process_network_connection_tracker_unittest.cc
@@ -0,0 +1,87 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/service/net/in_process_network_connection_tracker.h"
+
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "net/base/mock_network_change_notifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class TestNetworkConnectionObserver
+    : public network::NetworkConnectionTracker::NetworkConnectionObserver {
+ public:
+  explicit TestNetworkConnectionObserver(
+      network::NetworkConnectionTracker* tracker)
+      : tracker_(tracker) {
+    tracker_->AddNetworkConnectionObserver(this);
+  }
+
+  ~TestNetworkConnectionObserver() override {
+    tracker_->RemoveNetworkConnectionObserver(this);
+  }
+
+  void OnConnectionChanged(network::mojom::ConnectionType type) override {
+    call_count++;
+    last_type = type;
+  }
+
+  int call_count = 0;
+  network::mojom::ConnectionType last_type =
+      network::mojom::ConnectionType::CONNECTION_UNKNOWN;
+
+ private:
+  network::NetworkConnectionTracker* tracker_;
+};
+
+class InProcessNetworkConnectionTrackerTest : public ::testing::Test {
+ protected:
+  void SetConnectionType(net::NetworkChangeNotifier::ConnectionType type) {
+    notifier_.SetConnectionType(type);
+    notifier_.NotifyObserversOfNetworkChangeForTests(
+        notifier_.GetConnectionType());
+    task_environment_.RunUntilIdle();
+  }
+
+  network::NetworkConnectionTracker::ConnectionTypeCallback
+  UnreachedCallback() {
+    return base::BindOnce(
+        [](network::mojom::ConnectionType type) { NOTREACHED(); });
+  }
+
+ private:
+  base::test::ScopedTaskEnvironment task_environment_;
+  net::test::MockNetworkChangeNotifier notifier_;
+};
+
+// Tests that a registered observer gets called.
+TEST_F(InProcessNetworkConnectionTrackerTest, ObserverCalled) {
+  InProcessNetworkConnectionTracker tracker;
+  TestNetworkConnectionObserver observer(&tracker);
+
+  ASSERT_EQ(observer.call_count, 0);
+  SetConnectionType(net::NetworkChangeNotifier::ConnectionType::CONNECTION_3G);
+  ASSERT_EQ(observer.call_count, 1);
+  ASSERT_EQ(observer.last_type, network::mojom::ConnectionType::CONNECTION_3G);
+  SetConnectionType(net::NetworkChangeNotifier::ConnectionType::CONNECTION_4G);
+  ASSERT_EQ(observer.call_count, 2);
+  ASSERT_EQ(observer.last_type, network::mojom::ConnectionType::CONNECTION_4G);
+}
+
+// Tests that GetConnectionType returns synchronously.
+TEST_F(InProcessNetworkConnectionTrackerTest, GetConnectionTypeSync) {
+  SetConnectionType(
+      net::NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI);
+  InProcessNetworkConnectionTracker tracker;
+
+  auto type = network::mojom::ConnectionType::CONNECTION_UNKNOWN;
+  bool sync = tracker.GetConnectionType(&type, UnreachedCallback());
+  ASSERT_TRUE(sync);
+  ASSERT_EQ(type, network::mojom::ConnectionType::CONNECTION_WIFI);
+
+  SetConnectionType(net::NetworkChangeNotifier::ConnectionType::CONNECTION_2G);
+  sync = tracker.GetConnectionType(&type, UnreachedCallback());
+  ASSERT_TRUE(sync);
+  ASSERT_EQ(type, network::mojom::ConnectionType::CONNECTION_2G);
+}
diff --git a/chrome/service/service_process.cc b/chrome/service/service_process.cc
index 11bd3fc..89ef8e5d 100644
--- a/chrome/service/service_process.cc
+++ b/chrome/service/service_process.cc
@@ -170,6 +170,8 @@
   // The NetworkChangeNotifier must be created after TaskScheduler because it
   // posts tasks to it.
   network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
+  network_connection_tracker_ =
+      std::make_unique<InProcessNetworkConnectionTracker>();
 
   // Initialize the IO and FILE threads.
   base::Thread::Options options;
@@ -363,7 +365,8 @@
 cloud_print::CloudPrintProxy* ServiceProcess::GetCloudPrintProxy() {
   if (!cloud_print_proxy_.get()) {
     cloud_print_proxy_.reset(new cloud_print::CloudPrintProxy());
-    cloud_print_proxy_->Initialize(service_prefs_.get(), this);
+    cloud_print_proxy_->Initialize(service_prefs_.get(), this,
+                                   network_connection_tracker_.get());
   }
   return cloud_print_proxy_.get();
 }
diff --git a/chrome/service/service_process.h b/chrome/service/service_process.h
index a885956..01eee52 100644
--- a/chrome/service/service_process.h
+++ b/chrome/service/service_process.h
@@ -13,6 +13,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "chrome/service/cloud_print/cloud_print_proxy.h"
+#include "chrome/service/net/in_process_network_connection_tracker.h"
 #include "chrome/service/service_ipc_server.h"
 #include "mojo/public/cpp/platform/named_platform_channel.h"
 #include "mojo/public/cpp/platform/platform_channel_server_endpoint.h"
@@ -112,6 +113,8 @@
   void Terminate();
 
   std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
+  std::unique_ptr<InProcessNetworkConnectionTracker>
+      network_connection_tracker_;
   std::unique_ptr<base::Thread> io_thread_;
   std::unique_ptr<cloud_print::CloudPrintProxy> cloud_print_proxy_;
   std::unique_ptr<ServiceProcessPrefs> service_prefs_;
diff --git a/chrome/services/isolated_xr_device/xr_runtime_provider.cc b/chrome/services/isolated_xr_device/xr_runtime_provider.cc
index 0298898e..ae56236 100644
--- a/chrome/services/isolated_xr_device/xr_runtime_provider.cc
+++ b/chrome/services/isolated_xr_device/xr_runtime_provider.cc
@@ -24,6 +24,7 @@
     } else {
       client->OnDeviceAdded(oculus_device_->BindXRRuntimePtr(),
                             oculus_device_->BindGamepadFactory(),
+                            oculus_device_->BindCompositorHost(),
                             oculus_device_->GetVRDisplayInfo());
     }
   }
@@ -37,6 +38,7 @@
     } else {
       client->OnDeviceAdded(openvr_device_->BindXRRuntimePtr(),
                             openvr_device_->BindGamepadFactory(),
+                            openvr_device_->BindCompositorHost(),
                             openvr_device_->GetVRDisplayInfo());
     }
   }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index ddb534d..27048fd 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -4035,6 +4035,7 @@
         "../service/cloud_print/connector_settings_unittest.cc",
         "../service/cloud_print/printer_job_handler_unittest.cc",
         "../service/cloud_print/printer_job_queue_handler_unittest.cc",
+        "../service/net/in_process_network_connection_tracker_unittest.cc",
         "../service/service_ipc_server_unittest.cc",
         "../service/service_process_prefs_unittest.cc",
       ]
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
index 3dd47ad4..4a531d6 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/OmniboxTestUtils.java
@@ -333,7 +333,8 @@
         CriteriaHelper.pollUiThread(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                OmniboxSuggestionsList suggestionsList = locationBar.getSuggestionList();
+                OmniboxSuggestionsList suggestionsList =
+                        locationBar.getAutocompleteCoordinator().getSuggestionList();
                 if (suggestionsList == null) {
                     updateFailureReason("suggestionList is null");
                     return false;
@@ -361,7 +362,8 @@
         CriteriaHelper.pollUiThread(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                OmniboxSuggestionsList suggestionsList = locationBar.getSuggestionList();
+                OmniboxSuggestionsList suggestionsList =
+                        locationBar.getAutocompleteCoordinator().getSuggestionList();
                 return suggestionsList != null
                         && suggestionsList.isShown()
                         && suggestionsList.getCount() == expectedCount;
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 3cef335..caf3179 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -58,10 +58,6 @@
 
 const char kWindowHandlePrefix[] = "CDwindow-";
 
-std::string WebViewIdToWindowHandle(const std::string& web_view_id) {
-  return kWindowHandlePrefix + web_view_id;
-}
-
 bool WindowHandleToWebViewId(const std::string& window_handle,
                              std::string* web_view_id) {
   if (!base::StartsWith(window_handle, kWindowHandlePrefix,
@@ -86,6 +82,10 @@
 
 }  // namespace
 
+std::string WebViewIdToWindowHandle(const std::string& web_view_id) {
+  return kWindowHandlePrefix + web_view_id;
+}
+
 InitSessionParams::InitSessionParams(
     scoped_refptr<URLRequestContextGetter> context_getter,
     const SyncWebSocketFactory& socket_factory,
@@ -391,18 +391,6 @@
   return Status(kOk);
 }
 
-Status ExecuteGetCurrentWindowHandle(Session* session,
-                                     const base::DictionaryValue& params,
-                                     std::unique_ptr<base::Value>* value) {
-  WebView* web_view = NULL;
-  Status status = session->GetTargetWindow(&web_view);
-  if (status.IsError())
-    return status;
-
-  value->reset(new base::Value(WebViewIdToWindowHandle(web_view->GetId())));
-  return Status(kOk);
-}
-
 Status ExecuteLaunchApp(Session* session,
                         const base::DictionaryValue& params,
                         std::unique_ptr<base::Value>* value) {
diff --git a/chrome/test/chromedriver/session_commands.h b/chrome/test/chromedriver/session_commands.h
index b02ab4b..9bb9e5d 100644
--- a/chrome/test/chromedriver/session_commands.h
+++ b/chrome/test/chromedriver/session_commands.h
@@ -40,6 +40,8 @@
 
 bool MatchCapabilities(base::DictionaryValue* capabilities);
 
+std::string WebViewIdToWindowHandle(const std::string& web_view_id);
+
 // Initializes a session.
 Status ExecuteInitSession(const InitSessionParams& bound_params,
                           Session* session,
@@ -57,11 +59,6 @@
                                      const base::DictionaryValue& params,
                                      std::unique_ptr<base::Value>* value);
 
-// Retrieve the handle of the target window.
-Status ExecuteGetCurrentWindowHandle(Session* session,
-                                     const base::DictionaryValue& params,
-                                     std::unique_ptr<base::Value>* value);
-
 // Close the target window.
 Status ExecuteClose(Session* session,
                     const base::DictionaryValue& params,
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index 6044739..a8382d28 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -12,6 +12,14 @@
 
 _REVISION_NEGATIVE_FILTER = {}
 _REVISION_NEGATIVE_FILTER['HEAD'] = [
+    # marked as not yet implemented with chrome but already works
+    'ChildrenFindingTest.testShouldNotReturnRootElementWhenFindingChildrenById',
+    'ClearTest.shouldBeAbleToClearDateInput',
+    'ClearTest.shouldBeAbleToClearDatetimeLocalInput',
+    'ClearTest.shouldBeAbleToClearMonthInput',
+    'ClearTest.shouldBeAbleToClearTimeInput',
+    'ClearTest.shouldBeAbleToClearWeekInput',
+
     # Flaky: https://bugs.chromium.org/p/chromedriver/issues/detail?id=528
     'PageLoadingTest.testShouldDoNothingIfThereIsNothingToGoBackTo',
 
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index f7360859..a858f4b 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "chrome/test/chromedriver/window_commands.h"
+#include "chrome/test/chromedriver/session_commands.h"
 
 #include <stddef.h>
 
@@ -1580,3 +1581,12 @@
                                Timeout* timeout) {
   return web_view->TakeHeapSnapshot(value);
 }
+
+Status ExecuteGetCurrentWindowHandle(Session* session,
+                                     WebView* web_view,
+                                     const base::DictionaryValue& params,
+                                     std::unique_ptr<base::Value>* value,
+                                     Timeout* timeout) {
+  value->reset(new base::Value(WebViewIdToWindowHandle(web_view->GetId())));
+  return Status(kOk);
+}
diff --git a/chrome/test/chromedriver/window_commands.h b/chrome/test/chromedriver/window_commands.h
index 5e18353..e61a183 100644
--- a/chrome/test/chromedriver/window_commands.h
+++ b/chrome/test/chromedriver/window_commands.h
@@ -365,4 +365,12 @@
 Status ProcessInputActionSequence(Session* session,
                                   const base::DictionaryValue* action_sequence,
                                   std::unique_ptr<base::ListValue>* result);
+
+// Retrieve the handle of the target window.
+Status ExecuteGetCurrentWindowHandle(Session* session,
+                                     WebView* web_view,
+                                     const base::DictionaryValue& params,
+                                     std::unique_ptr<base::Value>* value,
+                                     Timeout* timeout);
+
 #endif  // CHROME_TEST_CHROMEDRIVER_WINDOW_COMMANDS_H_
diff --git a/chrome/test/data/extensions/api_test/tabs/pdf_extension_test.html b/chrome/test/data/extensions/api_test/tabs/pdf_extension_test.html
index bc235f8..0826c56 100644
--- a/chrome/test/data/extensions/api_test/tabs/pdf_extension_test.html
+++ b/chrome/test/data/extensions/api_test/tabs/pdf_extension_test.html
@@ -1,11 +1,10 @@
 <script>
 onbeforeunload=function(){
-        document.write('<b>Welcome to {Some Website}</b>');
-        document.title='OtherWebsite.ltd';
+  document.write('<b>Welcome to {Some Website}</b>');
+  document.title='OtherWebsite.ltd';
 };
 </script>
-<embed type="application/pdf" src="data:application/pdf;base64,JVBERi0xLjcKIAp0cmFpbGVyCjw8Ci9Sb290IDEgMCBSCj4+CiAKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKL09wZW5BY3Rpb24gMiAwIFIKPj4KZW5kb2JqCiAKMiAwIG9iago8PAovVHlwZSAvQWN0aW9uCi9TIC9VUkkKL1VSSSAoaHR0cDovL3d3dy5mYWNlYm9vay5jb206ODMpCj4+CmVuZG9iagogCiUlRU9G" width="640" height="480">
-
+<embed type="application/pdf" src="data:application/pdf;base64,JVBERi0xLjcKIAp0cmFpbGVyCjw8Ci9Sb290IDEgMCBSCj4+CiAKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCgoyIDAgb2JqCjw8Ci9UeXBlIC9QYWdlcwovQ291bnQgMQovS2lkcyBbMyAwIFJdCj4+CmVuZG9iagoKMyAwIG9iago8PAovVHlwZSAvUGFnZQovUGFyZW50IDIgMCBSCi9NZWRpYUJveCBbMCAwIDQwMCA0MDBdCi9SZXNvdXJjZXMgPDw+PgovQW5ub3RzIFs0IDAgUl0KPj4KZW5kb2JqCgo0IDAgb2JqCjw8Ci9UeXBlIC9Bbm5vdAovU3VidHlwZSAvTGluawovUmVjdCBbMCAwIDQwMCA0MDBdCi9BIDUgMCBSCj4+CmVuZG9iagoKNSAwIG9iago8PAovVHlwZSAvQWN0aW9uCi9TIC9VUkkKL1VSSSAoaHR0cDovL3d3dy5mYWNlYm9vay5jb206ODMpCj4+CmVuZG9iagoKJSVFT0Y=" width="640" height="480">
 
 <!--
 
@@ -23,12 +22,38 @@
 <<
 /Type /Catalog
 /Pages 2 0 R
-/OpenAction 2 0 R
 >>
 endobj
 
 2 0 obj
 <<
+/Type /Pages
+/Count 1
+/Kids [3 0 R]
+>>
+endobj
+
+3 0 obj
+<<
+/Type /Page
+/Parent 2 0 R
+/MediaBox [0 0 400 400]
+/Resources <<>>
+/Annots [4 0 R]
+>>
+endobj
+
+4 0 obj
+<<
+/Type /Annot
+/Subtype /Link
+/Rect [0 0 400 400]
+/A 5 0 R
+>>
+endobj
+
+5 0 obj
+<<
 /Type /Action
 /S /URI
 /URI (http://www.facebook.com:83)
diff --git a/chrome/test/data/local_ntp/local_ntp_browsertest.js b/chrome/test/data/local_ntp/local_ntp_browsertest.js
index 76b2111..a9e196d3 100644
--- a/chrome/test/data/local_ntp/local_ntp_browsertest.js
+++ b/chrome/test/data/local_ntp/local_ntp_browsertest.js
@@ -73,32 +73,6 @@
       window.chrome.embeddedSearch.newTabPage.mostVisited[0].rid));
 };
 
-/**
- * Tests that the GM2 style is applied when the flag is enabled.
- */
-test.localNtp.testMDApplied = function() {
-  // Turn off voice search to avoid reinitializing the speech object
-  configData.isVoiceSearchEnabled = false;
-
-  configData.isMDUIEnabled = true;
-  initLocalNTP(/*isGooglePage=*/true);
-  assertTrue(document.body.classList.contains('md'));
-}
-
-/**
- * Tests that the GM2 style is not applied when the flag is disabled.
- */
-test.localNtp.testMDNotApplied = function() {
-  // Turn off voice search to avoid reinitializing the speech object
-  configData.isVoiceSearchEnabled = false;
-
-  configData.isMDUIEnabled = false;
-  configData.isMDIconsEnabled = false;
-  configData.isCustomLinksEnabled = false;
-  initLocalNTP(/*isGooglePage=*/true);
-  assertFalse(document.body.classList.contains('md'));
-}
-
 
 // ****************************** ADVANCED TESTS ******************************
 // Advanced tests are controlled from the native side. The helpers here are
diff --git a/chrome/test/data/pdf/gesture_detector_test.js b/chrome/test/data/pdf/gesture_detector_test.js
index df56070..6f380f8d 100644
--- a/chrome/test/data/pdf/gesture_detector_test.js
+++ b/chrome/test/data/pdf/gesture_detector_test.js
@@ -248,38 +248,10 @@
     },
 
     function testPreventNativePinchZoom() {
-      let stubElement = new StubElement();
-      let gestureDetector = new GestureDetector(stubElement);
-      let pinchListener = new PinchListener(gestureDetector);
+      let pluginElement = viewer.plugin_;
+      let touchAction = window.getComputedStyle(pluginElement).touchAction;
 
-      // Ensure that the touchmove listener is not passive, otherwise the
-      // call to preventDefault will be ignored. Since listeners could default
-      // to being passive, we must set the value explicitly
-      // (see crbug.com/675730).
-      for (let l of stubElement.listeners.get('touchmove')) {
-        let options = l.options;
-        chrome.test.assertTrue(!!options &&
-                               typeof(options.passive) == 'boolean');
-        chrome.test.assertFalse(options.passive);
-      }
-
-      // We should not preventDefault the touchstart for 2 fingers, since this
-      // could just be a 2 finger tap.
-      let pinchStartEvent = new MockTouchEvent('touchstart', [
-        {clientX: 0, clientY: 0},
-        {clientX: 0, clientY: 2}
-      ]);
-      stubElement.sendEvent(pinchStartEvent);
-      chrome.test.assertEq('pinchstart', pinchListener.lastEvent.type);
-      chrome.test.assertFalse(pinchStartEvent.defaultPrevented);
-
-      let pinchUpdateEvent = new MockTouchEvent('touchmove', [
-        {clientX: 0, clientY: 0},
-        {clientX: 0, clientY: 4}
-      ]);
-      stubElement.sendEvent(pinchUpdateEvent);
-      chrome.test.assertEq('pinchupdate', pinchListener.lastEvent.type);
-      chrome.test.assertTrue(pinchUpdateEvent.defaultPrevented);
+      chrome.test.assertEq('pan-x pan-y', touchAction);
 
       chrome.test.succeed();
     },
diff --git a/components/OWNERS b/components/OWNERS
index a111e92..47fcc6a 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -3,8 +3,6 @@
 jochen@chromium.org
 sdefresne@chromium.org
 
-# Note: Best not to use globs (like autofill*) due to crbug.com/397984
-
 per-file app_modal_strings.grdp=file://components/app_modal/OWNERS
 per-file autofill_strings.grdp=file://components/autofill/OWNERS
 per-file bookmark_bar_strings.grdp=file://components/bookmarks/OWNERS
@@ -16,7 +14,6 @@
 per-file ntp_snippets_strings.grdp=file://components/ntp_snippets/OWNERS
 per-file omnibox_strings.grdp=file://components/omnibox/OWNERS
 per-file page_info_strings.grdp=file://chrome/browser/ui/page_info/OWNERS
-per-file page_info_strings_grdp=file://chrome/browser/ui/page_info/OWNERS
 per-file password_manager_strings.grdp=file://components/password_manager/OWNERS
 per-file payments_strings.grdp=file://components/payments/OWNERS
 per-file pdf_strings.grdp=file://pdf/OWNERS
diff --git a/components/autofill/android/BUILD.gn b/components/autofill/android/BUILD.gn
index f841fca..c952a263 100644
--- a/components/autofill/android/BUILD.gn
+++ b/components/autofill/android/BUILD.gn
@@ -80,6 +80,7 @@
   java_files = [
     "java/src/org/chromium/components/autofill/AutofillDelegate.java",
     "java/src/org/chromium/components/autofill/AutofillDropdownAdapter.java",
+    "java/src/org/chromium/components/autofill/AutofillDropdownFooter.java",
     "java/src/org/chromium/components/autofill/AutofillPopup.java",
     "java/src/org/chromium/components/autofill/AutofillSuggestion.java",
   ]
diff --git a/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml b/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml
new file mode 100644
index 0000000..da6e127e
--- /dev/null
+++ b/components/autofill/android/java/res/layout/autofill_dropdown_footer_item_refresh.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/autofill_dropdown_refresh_footer_item_height"
+    android:paddingEnd="@dimen/autofill_dropdown_refresh_horizontal_padding"
+    android:paddingStart="@dimen/autofill_dropdown_refresh_horizontal_padding"
+    android:gravity="center_vertical"
+    android:orientation="horizontal"
+    tools:ignore="UseCompoundDrawables" >
+
+    <TextView
+        android:id="@+id/dropdown_label"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:ellipsize="end"
+        android:includeFontPadding="false"
+        android:singleLine="true"
+        android:textAlignment="viewStart"
+        android:textAppearance="@style/BlackHint2" />
+
+    <ImageView
+        android:id="@+id/dropdown_icon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginStart="@dimen/autofill_dropdown_refresh_icon_margin"
+        android:layout_marginEnd="0dp"
+        tools:ignore="ContentDescription" />
+
+</LinearLayout>
diff --git a/components/autofill/android/java/res/values/dimens.xml b/components/autofill/android/java/res/values/dimens.xml
index ed876f8..3f01bcb1 100644
--- a/components/autofill/android/java/res/values/dimens.xml
+++ b/components/autofill/android/java/res/values/dimens.xml
@@ -14,6 +14,7 @@
 
     <!-- Dimens for refresh UI -->
     <dimen name="autofill_dropdown_refresh_item_height">48dp</dimen>
+    <dimen name="autofill_dropdown_refresh_footer_item_height">40dp</dimen>
     <dimen name="autofill_dropdown_refresh_horizontal_padding">16dp</dimen>
     <dimen name="autofill_dropdown_refresh_icon_margin">24dp</dimen>
 </resources>
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownFooter.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownFooter.java
new file mode 100644
index 0000000..82d9b068
--- /dev/null
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillDropdownFooter.java
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.components.autofill;
+
+import android.content.Context;
+import android.support.v7.content.res.AppCompatResources;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.chromium.ui.DropdownItem;
+
+import java.util.List;
+
+/**
+ * Renders the footer items in the Autofill dropdown, as provided by a List of DropdownItem objects.
+ */
+public class AutofillDropdownFooter extends LinearLayout {
+    /**
+     * Interface for handling selection events within the footer.
+     */
+    public interface Observer {
+        /**
+         * Invoked when an item in the footer is selected.
+         * @param item The data represented by this row.
+         */
+        void onFooterSelection(DropdownItem item);
+    }
+
+    /**
+     * View representing a single row in the footer.
+     */
+    private class FooterRow extends FrameLayout implements OnClickListener {
+        private DropdownItem mItem;
+        private Observer mObserver;
+
+        /**
+         * @param context Application context.
+         * @param item The DropdownItem representing the Autofill suggestion for this footer option.
+         * @param observer An object capable of responding to a selection of this row.
+         */
+        public FooterRow(Context context, DropdownItem item, Observer observer) {
+            super(context);
+            mItem = item;
+            mObserver = observer;
+            inflate(context, R.layout.autofill_dropdown_footer_item_refresh, this);
+            TextView label = findViewById(R.id.dropdown_label);
+            label.setText(item.getLabel());
+
+            ImageView icon = findViewById(R.id.dropdown_icon);
+            if (item.getIconId() == DropdownItem.NO_ICON) {
+                icon.setVisibility(View.GONE);
+            } else {
+                icon.setImageDrawable(AppCompatResources.getDrawable(context, item.getIconId()));
+            }
+
+            setOnClickListener(this);
+        }
+
+        @Override
+        public void onClick(View v) {
+            mObserver.onFooterSelection(mItem);
+        }
+    }
+
+    private Context mContext;
+
+    /**
+     * @param context Application context.
+     * @param items The item or items representing the content to be displayed in the footer. Each
+     *              item will be rendered as a row.
+     * @param observer An object capable of responding to a selection of a row in the footer.
+     */
+    public AutofillDropdownFooter(Context context, List<DropdownItem> items, Observer observer) {
+        super(context);
+        mContext = context;
+
+        setOrientation(LinearLayout.VERTICAL);
+
+        for (DropdownItem item : items) {
+            addView(new FooterRow(context, item, observer));
+        }
+    }
+}
diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillPopup.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillPopup.java
index 3af95dd..aa9bf8d 100644
--- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillPopup.java
+++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillPopup.java
@@ -24,9 +24,9 @@
 /**
  * The Autofill suggestion popup that lists relevant suggestions.
  */
-public class AutofillPopup extends DropdownPopupWindow implements AdapterView.OnItemClickListener,
-        AdapterView.OnItemLongClickListener, PopupWindow.OnDismissListener {
-
+public class AutofillPopup extends DropdownPopupWindow
+        implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener,
+                   PopupWindow.OnDismissListener, AutofillDropdownFooter.Observer {
     /**
      * We post a delayed runnable to clear accessibility focus from the autofill popup's list view
      * when we receive a {@code TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED} event because we receive a
@@ -75,17 +75,24 @@
     public void filterAndShow(AutofillSuggestion[] suggestions, boolean isRtl, boolean isRefresh) {
         mSuggestions = new ArrayList<AutofillSuggestion>(Arrays.asList(suggestions));
         // Remove the AutofillSuggestions with IDs that are not supported by Android
-        ArrayList<DropdownItem> cleanedData = new ArrayList<DropdownItem>();
+        List<DropdownItem> cleanedData = new ArrayList<>();
+        List<DropdownItem> footerRows = new ArrayList<>();
         HashSet<Integer> separators = new HashSet<Integer>();
         for (int i = 0; i < suggestions.length; i++) {
             int itemId = suggestions[i].getSuggestionId();
             if (itemId == PopupItemId.ITEM_ID_SEPARATOR) {
                 separators.add(cleanedData.size());
+            } else if (isFooter(itemId, isRefresh)) {
+                footerRows.add(suggestions[i]);
             } else {
                 cleanedData.add(suggestions[i]);
             }
         }
 
+        if (!footerRows.isEmpty()) {
+            setFooterView(new AutofillDropdownFooter(mContext, footerRows, this));
+        }
+
         setAdapter(new AutofillDropdownAdapter(mContext, cleanedData, separators, isRefresh));
         setRtl(isRtl);
         show();
@@ -129,4 +136,29 @@
     public void onDismiss() {
         mAutofillDelegate.dismissed();
     }
+
+    @Override
+    public void onFooterSelection(DropdownItem item) {
+        int index = mSuggestions.indexOf(item);
+        assert index > -1;
+        mAutofillDelegate.suggestionSelected(index);
+    }
+
+    private boolean isFooter(int row, boolean isRefresh) {
+        // Footer items are only handled as a special case in the refreshed UI.
+        if (!isRefresh) {
+            return false;
+        }
+
+        switch (row) {
+            case PopupItemId.ITEM_ID_CLEAR_FORM:
+            case PopupItemId.ITEM_ID_AUTOFILL_OPTIONS:
+            case PopupItemId.ITEM_ID_SCAN_CREDIT_CARD:
+            case PopupItemId.ITEM_ID_CREDIT_CARD_SIGNIN_PROMO:
+            case PopupItemId.ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY:
+                return true;
+            default:
+                return false;
+        }
+    }
 }
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index f78f2e3..80a3413b2 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1076,7 +1076,7 @@
   WebLocalFrame* frame = render_frame()->GetWebFrame();
   blink::WebURL url = frame->GetDocument().Url();
   if (url.ProtocolIs(url::kAboutScheme) || url.ProtocolIs(url::kBlobScheme) ||
-      url.ProtocolIs(url::kFileScheme))
+      url.ProtocolIs(url::kFileSystemScheme))
     return false;
   return frame->GetSecurityOrigin().CanAccessPasswordManager();
 }
diff --git a/components/autofill/core/browser/local_card_migration_manager.cc b/components/autofill/core/browser/local_card_migration_manager.cc
index 1a16152..8c1d8ef 100644
--- a/components/autofill/core/browser/local_card_migration_manager.cc
+++ b/components/autofill/core/browser/local_card_migration_manager.cc
@@ -61,6 +61,10 @@
   if (!IsCreditCardMigrationEnabled())
     return false;
 
+  // Don't show the the prompt if user cancelled/rejected previously.
+  if (prefs::IsLocalCardMigrationPromptPreviouslyCancelled(client_->GetPrefs()))
+    return false;
+
   // Fetch all migratable credit cards and store in |migratable_credit_cards_|.
   GetMigratableCreditCards();
 
diff --git a/components/autofill/core/browser/local_card_migration_manager_unittest.cc b/components/autofill/core/browser/local_card_migration_manager_unittest.cc
index b18ee7d..978328e 100644
--- a/components/autofill/core/browser/local_card_migration_manager_unittest.cc
+++ b/components/autofill/core/browser/local_card_migration_manager_unittest.cc
@@ -695,6 +695,44 @@
   EXPECT_TRUE(local_card_migration_manager_->MainPromptWasShown());
 }
 
+// Verify that when triggering from submitted form, intermediate prompt and main
+// prompt are not triggered as user previously rejected the prompt.
+TEST_F(LocalCardMigrationManagerTest,
+       MigrateCreditCard_DontTriggerFromSubmittedForm) {
+  EnableAutofillCreditCardLocalCardMigrationExperiment();
+
+  // Set the billing_customer_number Priority Preference to designate
+  // existence of a Payments account.
+  autofill_client_.GetPrefs()->SetDouble(prefs::kAutofillBillingCustomerNumber,
+                                         12345);
+
+  // Set that previously user rejected this prompt.
+  prefs::SetLocalCardMigrationPromptPreviouslyCancelled(
+      autofill_client_.GetPrefs(), true);
+
+  // Add a local credit card whose |TypeAndLastFourDigits| matches what we will
+  // enter below.
+  AddLocalCrediCard(personal_data_, "Flo Master", "4111111111111111", "11",
+                    test::NextYear().c_str(), "1", "guid1");
+  // Add another local credit card, so it will trigger migration.
+  AddLocalCrediCard(personal_data_, "Flo Master", "5555555555554444", "11",
+                    test::NextYear().c_str(), "1", "guid2");
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  test::CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, and submit.
+  EditCreditCardFrom(credit_card_form, "Flo Master", "4111111111111111", "11",
+                     test::NextYear().c_str(), "123");
+  // Migration should not be offered because user previously rejected
+  // migration prompt.
+  FormSubmitted(credit_card_form);
+  EXPECT_FALSE(local_card_migration_manager_->IntermediatePromptWasShown());
+  EXPECT_FALSE(local_card_migration_manager_->MainPromptWasShown());
+}
+
 // Verify that given the parsed response from the payments client, the migration
 // status is correctly set.
 TEST_F(LocalCardMigrationManagerTest, MigrateCreditCard_MigrationSuccess) {
diff --git a/components/autofill/core/common/autofill_prefs.cc b/components/autofill/core/common/autofill_prefs.cc
index 1d1d054..c648579 100644
--- a/components/autofill/core/common/autofill_prefs.cc
+++ b/components/autofill/core/common/autofill_prefs.cc
@@ -54,6 +54,11 @@
 const char kAutofillLastVersionDisusedCreditCardsDeleted[] =
     "autofill.last_version_disused_credit_cards_deleted";
 
+// Boolean that is set to denote whether user cancelled/rejected local card
+// migration prompt.
+const char kAutofillMigrateLocalCardsCancelledPrompt[] =
+    "autofill.migrate_local_card_cancelled_state";
+
 // Boolean that is true if the orphan rows in the autofill table were removed.
 const char kAutofillOrphanRowsRemoved[] = "autofill.orphan_rows_removed";
 
@@ -116,6 +121,8 @@
       prefs::PREVIOUS_SAVE_CREDIT_CARD_PROMPT_USER_DECISION_NONE);
   registry->RegisterIntegerPref(
       prefs::kAutofillLastVersionDisusedCreditCardsDeleted, 0);
+  registry->RegisterBooleanPref(
+      prefs::kAutofillMigrateLocalCardsCancelledPrompt, false);
   registry->RegisterBooleanPref(prefs::kAutofillOrphanRowsRemoved, false);
   registry->RegisterDictionaryPref(prefs::kAutofillUploadEvents);
   registry->RegisterTimePref(prefs::kAutofillUploadEventsLastResetTimestamp,
@@ -165,6 +172,14 @@
   SetCreditCardAutofillEnabled(prefs, enabled);
 }
 
+bool IsCreditCardAutofillEnabled(const PrefService* prefs) {
+  return prefs->GetBoolean(kAutofillCreditCardEnabled);
+}
+
+void SetCreditCardAutofillEnabled(PrefService* prefs, bool enabled) {
+  prefs->SetBoolean(kAutofillCreditCardEnabled, enabled);
+}
+
 bool IsAutofillManaged(const PrefService* prefs) {
   return prefs->IsManagedPreference(kAutofillEnabledDeprecated);
 }
@@ -185,12 +200,13 @@
   prefs->SetBoolean(kAutofillProfileEnabled, enabled);
 }
 
-bool IsCreditCardAutofillEnabled(const PrefService* prefs) {
-  return prefs->GetBoolean(kAutofillCreditCardEnabled);
+bool IsLocalCardMigrationPromptPreviouslyCancelled(const PrefService* prefs) {
+  return prefs->GetBoolean(kAutofillMigrateLocalCardsCancelledPrompt);
 }
 
-void SetCreditCardAutofillEnabled(PrefService* prefs, bool enabled) {
-  prefs->SetBoolean(kAutofillCreditCardEnabled, enabled);
+void SetLocalCardMigrationPromptPreviouslyCancelled(PrefService* prefs,
+                                                    bool enabled) {
+  prefs->SetBoolean(kAutofillMigrateLocalCardsCancelledPrompt, enabled);
 }
 
 bool IsPaymentsIntegrationEnabled(const PrefService* prefs) {
diff --git a/components/autofill/core/common/autofill_prefs.h b/components/autofill/core/common/autofill_prefs.h
index aee9128..08d2ce3 100644
--- a/components/autofill/core/common/autofill_prefs.h
+++ b/components/autofill/core/common/autofill_prefs.h
@@ -29,14 +29,15 @@
 extern const char kAutofillLastVersionDeduped[];
 extern const char kAutofillLastVersionDisusedAddressesDeleted[];
 extern const char kAutofillLastVersionDisusedCreditCardsDeleted[];
+extern const char kAutofillMigrateLocalCardsCancelledPrompt[];
 extern const char kAutofillOrphanRowsRemoved[];
 // Do not get/set the value of this pref directly. Use provided getter/setter.
 extern const char kAutofillProfileEnabled[];
+extern const char kAutofillProfileValidity[];
 extern const char kAutofillUploadEvents[];
 extern const char kAutofillUploadEventsLastResetTimestamp[];
 extern const char kAutofillWalletImportEnabled[];
 extern const char kAutofillWalletImportStorageCheckboxState[];
-extern const char kAutofillProfileValidity[];
 
 // Possible values for previous user decision when we displayed a save credit
 // card prompt.
@@ -59,6 +60,10 @@
 
 void SetAutofillEnabled(PrefService* prefs, bool enabled);
 
+bool IsCreditCardAutofillEnabled(const PrefService* prefs);
+
+void SetCreditCardAutofillEnabled(PrefService* prefs, bool enabled);
+
 bool IsAutofillManaged(const PrefService* prefs);
 
 bool IsProfileAutofillManaged(const PrefService* prefs);
@@ -69,9 +74,10 @@
 
 void SetProfileAutofillEnabled(PrefService* prefs, bool enabled);
 
-bool IsCreditCardAutofillEnabled(const PrefService* prefs);
+bool IsLocalCardMigrationPromptPreviouslyCancelled(const PrefService* prefs);
 
-void SetCreditCardAutofillEnabled(PrefService* prefs, bool enabled);
+void SetLocalCardMigrationPromptPreviouslyCancelled(PrefService* prefs,
+                                                    bool enabled);
 
 bool IsPaymentsIntegrationEnabled(const PrefService* prefs);
 
diff --git a/components/autofill_assistant/browser/ui_controller.h b/components/autofill_assistant/browser/ui_controller.h
index db7d91e2..3c35482 100644
--- a/components/autofill_assistant/browser/ui_controller.h
+++ b/components/autofill_assistant/browser/ui_controller.h
@@ -43,12 +43,16 @@
   // Show UI to ask user to choose an address in personal data manager. GUID of
   // the chosen address will be returned through callback, otherwise empty
   // string if the user chose to continue manually.
+  // TODO(806868): Return full address object instead of GUID (the GUID can
+  // change after synchronization with the server).
   virtual void ChooseAddress(
       base::OnceCallback<void(const std::string&)> callback) = 0;
 
   // Show UI to ask user to choose a card in personal data manager. GUID of the
   // chosen card will be returned through callback, otherwise empty string if
   // the user chose to continue manually.
+  // TODO(806868): Return full card object instead of GUID (the GUID can change
+  // after synchronization with the server).
   virtual void ChooseCard(
       base::OnceCallback<void(const std::string&)> callback) = 0;
 
diff --git a/components/browsing_data/core/counters/passwords_counter.cc b/components/browsing_data/core/counters/passwords_counter.cc
index c58ecdd4..eac911c7 100644
--- a/components/browsing_data/core/counters/passwords_counter.cc
+++ b/components/browsing_data/core/counters/passwords_counter.cc
@@ -54,17 +54,22 @@
   store_->GetAutofillableLogins(this);
 }
 
+std::unique_ptr<BrowsingDataCounter::SyncResult>
+PasswordsCounter::MakeResult() {
+  return std::make_unique<BrowsingDataCounter::SyncResult>(this, num_passwords_,
+                                                           is_sync_active());
+}
+
 void PasswordsCounter::OnGetPasswordStoreResults(
     std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
   base::Time start = GetPeriodStart();
   base::Time end = GetPeriodEnd();
-  int num_passwords = std::count_if(
+  num_passwords_ = std::count_if(
       results.begin(), results.end(),
       [start, end](const std::unique_ptr<autofill::PasswordForm>& form) {
         return (form->date_created >= start && form->date_created < end);
       });
-  ReportResult(std::make_unique<SyncResult>(this, num_passwords,
-                                            sync_tracker_.IsSyncActive()));
+  ReportResult(MakeResult());
 }
 
 void PasswordsCounter::OnLoginsChanged(
diff --git a/components/browsing_data/core/counters/passwords_counter.h b/components/browsing_data/core/counters/passwords_counter.h
index bfdb086..901a07c2 100644
--- a/components/browsing_data/core/counters/passwords_counter.h
+++ b/components/browsing_data/core/counters/passwords_counter.h
@@ -26,6 +26,12 @@
 
   const char* GetPrefName() const override;
 
+ protected:
+  virtual std::unique_ptr<SyncResult> MakeResult();
+
+  bool is_sync_active() { return sync_tracker_.IsSyncActive(); };
+  int num_passwords() { return num_passwords_; }
+
  private:
   void OnInitialized() override;
 
@@ -44,6 +50,7 @@
   base::CancelableTaskTracker cancelable_task_tracker_;
   scoped_refptr<password_manager::PasswordStore> store_;
   SyncTracker sync_tracker_;
+  int num_passwords_;
 };
 
 }  // namespace browsing_data
diff --git a/components/cronet/android/BUILD.gn b/components/cronet/android/BUILD.gn
index 791de37b..604ffdf 100644
--- a/components/cronet/android/BUILD.gn
+++ b/components/cronet/android/BUILD.gn
@@ -898,6 +898,7 @@
       "test/src/org/chromium/net/MockUrlRequestJobFactory.java",
       "test/src/org/chromium/net/NativeTestServer.java",
       "test/src/org/chromium/net/QuicTestServer.java",
+      "test/src/org/chromium/net/ReportingCollector.java",
       "test/src/org/chromium/net/TestFilesInstaller.java",
       "test/src/org/chromium/net/TestUploadDataStreamHandler.java",
     ]
@@ -1000,6 +1001,7 @@
       "test/javatests/src/org/chromium/net/GetStatusTest.java",
       "test/javatests/src/org/chromium/net/MetricsTestUtil.java",
       "test/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java",
+      "test/javatests/src/org/chromium/net/NetworkErrorLoggingTest.java",
       "test/javatests/src/org/chromium/net/NQETest.java",
       "test/javatests/src/org/chromium/net/PkpTest.java",
       "test/javatests/src/org/chromium/net/QuicTest.java",
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/NetworkErrorLoggingTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/NetworkErrorLoggingTest.java
new file mode 100644
index 0000000..98d6e3d
--- /dev/null
+++ b/components/cronet/android/test/javatests/src/org/chromium/net/NetworkErrorLoggingTest.java
@@ -0,0 +1,179 @@
+// 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.net;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import static org.chromium.net.CronetTestRule.SERVER_CERT_PEM;
+import static org.chromium.net.CronetTestRule.SERVER_KEY_PKCS8_PEM;
+import static org.chromium.net.CronetTestRule.getContext;
+
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+import org.chromium.base.test.util.Feature;
+import org.chromium.net.CronetTestRule.OnlyRunNativeCronet;
+
+/**
+ * Tests requests that generate Network Error Logging reports.
+ */
+@RunWith(BaseJUnit4ClassRunner.class)
+public class NetworkErrorLoggingTest {
+    @Rule
+    public final CronetTestRule mTestRule = new CronetTestRule();
+
+    private CronetEngine mCronetEngine;
+
+    @Before
+    public void setUp() throws Exception {
+        TestFilesInstaller.installIfNeeded(getContext());
+        assertTrue(Http2TestServer.startHttp2TestServer(
+                getContext(), SERVER_CERT_PEM, SERVER_KEY_PKCS8_PEM));
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        assertTrue(Http2TestServer.shutdownHttp2TestServer());
+        if (mCronetEngine != null) {
+            mCronetEngine.shutdown();
+        }
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Cronet"})
+    @OnlyRunNativeCronet
+    public void testManualReportUpload() throws Exception {
+        ExperimentalCronetEngine.Builder builder =
+                new ExperimentalCronetEngine.Builder(getContext());
+        CronetTestUtil.setMockCertVerifierForTesting(
+                builder, QuicTestServer.createMockCertVerifier());
+        mCronetEngine = builder.build();
+        String url = Http2TestServer.getReportingCollectorUrl();
+        TestUrlRequestCallback callback = new TestUrlRequestCallback();
+        UrlRequest.Builder requestBuilder =
+                mCronetEngine.newUrlRequestBuilder(url, callback, callback.getExecutor());
+        TestUploadDataProvider dataProvider = new TestUploadDataProvider(
+                TestUploadDataProvider.SuccessCallbackMode.SYNC, callback.getExecutor());
+        dataProvider.addRead("[{\"type\": \"test_report\"}]".getBytes());
+        requestBuilder.setUploadDataProvider(dataProvider, callback.getExecutor());
+        requestBuilder.addHeader("Content-Type", "application/reports+json");
+        requestBuilder.build().start();
+        callback.blockForDone();
+        dataProvider.assertClosed();
+        assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+        assertTrue(Http2TestServer.getReportingCollector().containsReport(
+                "{\"type\": \"test_report\"}"));
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Cronet"})
+    @OnlyRunNativeCronet
+    public void testUploadNELReportsFromHeaders() throws Exception {
+        ExperimentalCronetEngine.Builder builder =
+                new ExperimentalCronetEngine.Builder(getContext());
+        builder.setExperimentalOptions("{\"NetworkErrorLogging\": {\"enable\": true}}");
+        CronetTestUtil.setMockCertVerifierForTesting(
+                builder, QuicTestServer.createMockCertVerifier());
+        mCronetEngine = builder.build();
+        String url = Http2TestServer.getSuccessWithNELHeadersUrl();
+        TestUrlRequestCallback callback = new TestUrlRequestCallback();
+        UrlRequest.Builder requestBuilder =
+                mCronetEngine.newUrlRequestBuilder(url, callback, callback.getExecutor());
+        requestBuilder.build().start();
+        callback.blockForDone();
+        assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+        Http2TestServer.getReportingCollector().waitForReports(1);
+        assertTrue(Http2TestServer.getReportingCollector().containsReport(""
+                + "{"
+                + "  \"type\": \"network-error\","
+                + "  \"url\": \"" + url + "\","
+                + "  \"body\": {"
+                + "    \"method\": \"GET\","
+                + "    \"phase\": \"application\","
+                + "    \"protocol\": \"h2\","
+                + "    \"referrer\": \"\","
+                + "    \"sampling_fraction\": 1.0,"
+                + "    \"server_ip\": \"127.0.0.1\","
+                + "    \"status_code\": 200,"
+                + "    \"type\": \"ok\""
+                + "  }"
+                + "}"));
+    }
+
+    @Test
+    @SmallTest
+    @Feature({"Cronet"})
+    @OnlyRunNativeCronet
+    public void testUploadNELReportsFromPreloadedPolicy() throws Exception {
+        ExperimentalCronetEngine.Builder builder =
+                new ExperimentalCronetEngine.Builder(getContext());
+        String serverOrigin = Http2TestServer.getServerUrl();
+        String collectorUrl = Http2TestServer.getReportingCollectorUrl();
+        builder.setExperimentalOptions(""
+                + "{\"NetworkErrorLogging\": {"
+                + "  \"enable\": true,"
+                + "  \"preloaded_report_to_headers\": ["
+                + "    {"
+                + "      \"origin\": \"" + serverOrigin + "\","
+                + "      \"value\": {"
+                + "        \"group\": \"nel\","
+                + "        \"max_age\": 86400,"
+                + "        \"endpoints\": ["
+                + "          {\"url\": \"" + collectorUrl + "\"}"
+                + "        ]"
+                + "      }"
+                + "    }"
+                + "  ],"
+                + "  \"preloaded_nel_headers\": ["
+                + "    {"
+                + "      \"origin\": \"" + serverOrigin + "\","
+                + "      \"value\": {"
+                + "        \"report_to\": \"nel\","
+                + "        \"max_age\": 86400,"
+                + "        \"success_fraction\": 1.0"
+                + "      }"
+                + "    }"
+                + "  ]"
+                + "}}");
+        CronetTestUtil.setMockCertVerifierForTesting(
+                builder, QuicTestServer.createMockCertVerifier());
+        mCronetEngine = builder.build();
+        String url = Http2TestServer.getEchoMethodUrl();
+        TestUrlRequestCallback callback = new TestUrlRequestCallback();
+        UrlRequest.Builder requestBuilder =
+                mCronetEngine.newUrlRequestBuilder(url, callback, callback.getExecutor());
+        requestBuilder.build().start();
+        callback.blockForDone();
+        assertEquals(200, callback.mResponseInfo.getHttpStatusCode());
+        Http2TestServer.getReportingCollector().waitForReports(1);
+        // Note that because we don't know in advance what the server IP address is for preloaded
+        // origins, we'll always get a "downgraded" dns.address_changed NEL report if we don't
+        // receive a replacement NEL policy with the request.
+        assertTrue(Http2TestServer.getReportingCollector().containsReport(""
+                + "{"
+                + "  \"type\": \"network-error\","
+                + "  \"url\": \"" + url + "\","
+                + "  \"body\": {"
+                + "    \"method\": \"GET\","
+                + "    \"phase\": \"dns\","
+                + "    \"protocol\": \"h2\","
+                + "    \"referrer\": \"\","
+                + "    \"sampling_fraction\": 1.0,"
+                + "    \"server_ip\": \"127.0.0.1\","
+                + "    \"status_code\": 0,"
+                + "    \"type\": \"dns.address_changed\""
+                + "  }"
+                + "}"));
+    }
+}
diff --git a/components/cronet/android/test/src/org/chromium/net/Http2TestHandler.java b/components/cronet/android/test/src/org/chromium/net/Http2TestHandler.java
index f49e94e..06518603 100644
--- a/components/cronet/android/test/src/org/chromium/net/Http2TestHandler.java
+++ b/components/cronet/android/test/src/org/chromium/net/Http2TestHandler.java
@@ -6,12 +6,16 @@
 
 import org.chromium.base.Log;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 
 import static io.netty.buffer.Unpooled.copiedBuffer;
 import static io.netty.buffer.Unpooled.unreleasableBuffer;
+import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
 import static io.netty.handler.codec.http.HttpResponseStatus.OK;
 import static io.netty.handler.logging.LogLevel.INFO;
 
@@ -42,6 +46,8 @@
     public static final String ECHO_STREAM_PATH = "/echostream";
     public static final String ECHO_TRAILERS_PATH = "/echotrailers";
     public static final String SERVE_SIMPLE_BROTLI_RESPONSE = "/simplebrotli";
+    public static final String REPORTING_COLLECTOR_PATH = "/reporting-collector";
+    public static final String SUCCESS_WITH_NEL_HEADERS_PATH = "/success-with-nel";
 
     private static final String TAG = Http2TestHandler.class.getSimpleName();
     private static final Http2FrameLogger sLogger =
@@ -51,6 +57,9 @@
 
     private HashMap<Integer, RequestResponder> mResponderMap = new HashMap<>();
 
+    private ReportingCollector mReportingCollector;
+    private String mServerUrl;
+
     /**
      * Builder for HTTP/2 test handler.
      */
@@ -60,6 +69,16 @@
             frameLogger(sLogger);
         }
 
+        public Builder setReportingCollector(ReportingCollector reportingCollector) {
+            mReportingCollector = reportingCollector;
+            return this;
+        }
+
+        public Builder setServerUrl(String serverUrl) {
+            mServerUrl = serverUrl;
+            return this;
+        }
+
         @Override
         public Http2TestHandler build() {
             return super.build();
@@ -68,10 +87,14 @@
         @Override
         protected Http2TestHandler build(Http2ConnectionDecoder decoder,
                 Http2ConnectionEncoder encoder, Http2Settings initialSettings) {
-            Http2TestHandler handler = new Http2TestHandler(decoder, encoder, initialSettings);
+            Http2TestHandler handler = new Http2TestHandler(
+                    decoder, encoder, initialSettings, mReportingCollector, mServerUrl);
             frameListener(handler);
             return handler;
         }
+
+        private ReportingCollector mReportingCollector;
+        private String mServerUrl;
     }
 
     private class RequestResponder {
@@ -193,6 +216,76 @@
         }
     }
 
+    // A RequestResponder that implements a Reporting collector.
+    private class ReportingCollectorResponder extends RequestResponder {
+        private ByteArrayOutputStream mPartialPayload = new ByteArrayOutputStream();
+
+        @Override
+        void onHeadersRead(ChannelHandlerContext ctx, int streamId, boolean endOfStream,
+                Http2Headers headers) {}
+
+        @Override
+        int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
+                boolean endOfStream) {
+            int processed = data.readableBytes() + padding;
+            try {
+                data.readBytes(mPartialPayload, data.readableBytes());
+            } catch (IOException e) {
+            }
+            if (endOfStream) {
+                processPayload(ctx, streamId);
+            }
+            return processed;
+        }
+
+        private void processPayload(ChannelHandlerContext ctx, int streamId) {
+            boolean succeeded = false;
+            try {
+                String payload = mPartialPayload.toString(CharsetUtil.UTF_8.name());
+                succeeded = mReportingCollector.addReports(payload);
+            } catch (UnsupportedEncodingException e) {
+            }
+            Http2Headers responseHeaders;
+            if (succeeded) {
+                responseHeaders = new DefaultHttp2Headers().status(OK.codeAsText());
+            } else {
+                responseHeaders = new DefaultHttp2Headers().status(BAD_REQUEST.codeAsText());
+            }
+            encoder().writeHeaders(ctx, streamId, responseHeaders, 0, true, ctx.newPromise());
+            ctx.flush();
+        }
+    }
+
+    // A RequestResponder that serves a successful response with Reporting and NEL headers
+    private class SuccessWithNELHeadersResponder extends RequestResponder {
+        @Override
+        void onHeadersRead(ChannelHandlerContext ctx, int streamId, boolean endOfStream,
+                Http2Headers headers) {
+            Http2Headers responseHeaders = new DefaultHttp2Headers().status(OK.codeAsText());
+            responseHeaders.add("report-to", getReportToHeader());
+            responseHeaders.add("nel", getNELHeader());
+            encoder().writeHeaders(ctx, streamId, responseHeaders, 0, true, ctx.newPromise());
+            ctx.flush();
+        }
+
+        @Override
+        int onDataRead(ChannelHandlerContext ctx, int streamId, ByteBuf data, int padding,
+                boolean endOfStream) {
+            int processed = data.readableBytes() + padding;
+            return processed;
+        }
+
+        private String getReportToHeader() {
+            return String.format("{\"group\": \"nel\", \"max_age\": 86400, "
+                            + "\"endpoints\": [{\"url\": \"%s%s\"}]}",
+                    mServerUrl, REPORTING_COLLECTOR_PATH);
+        }
+
+        private String getNELHeader() {
+            return "{\"report_to\": \"nel\", \"max_age\": 86400, \"success_fraction\": 1.0}";
+        }
+    }
+
     private static Http2Headers createDefaultResponseHeaders() {
         return new DefaultHttp2Headers().status(OK.codeAsText());
     }
@@ -212,8 +305,11 @@
     }
 
     private Http2TestHandler(Http2ConnectionDecoder decoder, Http2ConnectionEncoder encoder,
-            Http2Settings initialSettings) {
+            Http2Settings initialSettings, ReportingCollector reportingCollector,
+            String serverUrl) {
         super(decoder, encoder, initialSettings);
+        mReportingCollector = reportingCollector;
+        mServerUrl = serverUrl;
     }
 
     @Override
@@ -251,6 +347,10 @@
             responder = new EchoMethodResponder();
         } else if (path.startsWith(SERVE_SIMPLE_BROTLI_RESPONSE)) {
             responder = new ServeSimpleBrotliResponder();
+        } else if (path.startsWith(REPORTING_COLLECTOR_PATH)) {
+            responder = new ReportingCollectorResponder();
+        } else if (path.startsWith(SUCCESS_WITH_NEL_HEADERS_PATH)) {
+            responder = new SuccessWithNELHeadersResponder();
         } else {
             responder = new RequestResponder();
         }
diff --git a/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java b/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java
index 51deecfa..0da9937 100644
--- a/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java
+++ b/components/cronet/android/test/src/org/chromium/net/Http2TestServer.java
@@ -45,10 +45,13 @@
     // Server port.
     private static final int PORT = 8443;
 
+    private static ReportingCollector sReportingCollector;
+
     public static boolean shutdownHttp2TestServer() throws Exception {
         if (sServerChannel != null) {
             sServerChannel.close().sync();
             sServerChannel = null;
+            sReportingCollector = null;
             return true;
         }
         return false;
@@ -66,6 +69,10 @@
         return "https://" + HOST + ":" + PORT;
     }
 
+    public static ReportingCollector getReportingCollector() {
+        return sReportingCollector;
+    }
+
     public static String getEchoAllHeadersUrl() {
         return getServerUrl() + Http2TestHandler.ECHO_ALL_HEADERS_PATH;
     }
@@ -99,8 +106,23 @@
         return getServerUrl() + Http2TestHandler.SERVE_SIMPLE_BROTLI_RESPONSE;
     }
 
+    /**
+     * @return url of the reporting collector
+     */
+    public static String getReportingCollectorUrl() {
+        return getServerUrl() + Http2TestHandler.REPORTING_COLLECTOR_PATH;
+    }
+
+    /**
+     * @return url of a resource that includes Reporting and NEL policy headers in its response
+     */
+    public static String getSuccessWithNELHeadersUrl() {
+        return getServerUrl() + Http2TestHandler.SUCCESS_WITH_NEL_HEADERS_PATH;
+    }
+
     public static boolean startHttp2TestServer(
             Context context, String certFileName, String keyFileName) throws Exception {
+        sReportingCollector = new ReportingCollector();
         Http2TestServerRunnable http2TestServerRunnable =
                 new Http2TestServerRunnable(new File(CertTestUtil.CERTS_DIRECTORY + certFileName),
                         new File(CertTestUtil.CERTS_DIRECTORY + keyFileName));
@@ -185,7 +207,10 @@
         protected void configurePipeline(ChannelHandlerContext ctx, String protocol)
                 throws Exception {
             if (ApplicationProtocolNames.HTTP_2.equals(protocol)) {
-                ctx.pipeline().addLast(new Http2TestHandler.Builder().build());
+                ctx.pipeline().addLast(new Http2TestHandler.Builder()
+                                               .setReportingCollector(sReportingCollector)
+                                               .setServerUrl(getServerUrl())
+                                               .build());
                 return;
             }
 
diff --git a/components/cronet/android/test/src/org/chromium/net/ReportingCollector.java b/components/cronet/android/test/src/org/chromium/net/ReportingCollector.java
new file mode 100644
index 0000000..a120bda
--- /dev/null
+++ b/components/cronet/android/test/src/org/chromium/net/ReportingCollector.java
@@ -0,0 +1,109 @@
+// 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.net;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Stores Reporting API reports received by a test collector, providing helper methods for checking
+ * whether expected reports were actually received.
+ */
+class ReportingCollector {
+    private ArrayList<JSONObject> mReceivedReports = new ArrayList<JSONObject>();
+    private Semaphore mReceivedReportsSemaphore = new Semaphore(0);
+
+    /**
+     * Stores a batch of uploaded reports.
+     * @param payload the POST payload from the upload
+     * @return whether the payload was parsed successfully
+     */
+    public boolean addReports(String payload) {
+        try {
+            JSONArray reports = new JSONArray(payload);
+            int elementCount = 0;
+            synchronized (mReceivedReports) {
+                for (int i = 0; i < reports.length(); i++) {
+                    JSONObject element = reports.optJSONObject(i);
+                    if (element != null) {
+                        mReceivedReports.add(element);
+                        elementCount++;
+                    }
+                }
+            }
+            mReceivedReportsSemaphore.release(elementCount);
+            return true;
+        } catch (JSONException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Checks whether a report with the given payload exists or not.
+     */
+    public boolean containsReport(String expected) {
+        try {
+            JSONObject expectedReport = new JSONObject(expected);
+            synchronized (mReceivedReports) {
+                for (JSONObject received : mReceivedReports) {
+                    if (isJSONObjectSubset(expectedReport, received)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        } catch (JSONException e) {
+            return false;
+        }
+    }
+
+    /**
+     * Waits until the requested number of reports have been received, with a 5-second timeout.
+     */
+    public void waitForReports(int reportCount) {
+        final int timeoutSeconds = 5;
+        try {
+            mReceivedReportsSemaphore.tryAcquire(reportCount, timeoutSeconds, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+        }
+    }
+
+    /**
+     * Checks whether one {@link JSONObject} is a subset of another.  Any fields that appear in
+     * {@code lhs} must also appear in {@code rhs}, with the same value.  There can be extra fields
+     * in {@code rhs}; if so, they are ignored.
+     */
+    private boolean isJSONObjectSubset(JSONObject lhs, JSONObject rhs) {
+        Iterator<String> keys = lhs.keys();
+        while (keys.hasNext()) {
+            String key = keys.next();
+            Object lhsElement = lhs.opt(key);
+            Object rhsElement = rhs.opt(key);
+
+            if (rhsElement == null) {
+                // lhs has an element that doesn't appear in rhs
+                return false;
+            }
+
+            if (lhsElement instanceof JSONObject) {
+                if (!(rhsElement instanceof JSONObject)) {
+                    return false;
+                }
+                return isJSONObjectSubset((JSONObject) lhsElement, (JSONObject) rhsElement);
+            }
+
+            if (!lhsElement.equals(rhsElement)) {
+                return false;
+            }
+        }
+        return true;
+    }
+};
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index ad190c9b..5e860b4 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -22,6 +22,7 @@
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
 #include "components/data_reduction_proxy/core/common/lofi_decider.h"
@@ -684,6 +685,11 @@
     const net::URLRequest& request) const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
+  if (base::FeatureList::IsEnabled(
+          features::kDataReductionProxyBrotliHoldback)) {
+    return;
+  }
+
   // This method should be called only when the resolved proxy was a data
   // saver proxy.
   DCHECK(data_reduction_proxy_config_->FindConfiguredDataReductionProxy(
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index 83007443..2fb9cb23 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -1711,6 +1711,32 @@
   FetchURLRequestAndVerifyBrotli(nullptr, response_headers, false, false);
 }
 
+// Test that Brotli is not added to the accept-encoding header when
+// kDataReductionProxyBrotliHoldback feature is enabled.
+TEST_F(DataReductionProxyNetworkDelegateTest,
+       BrotliAdvertisement_BrotliHoldbackEnabled) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  scoped_feature_list.InitAndEnableFeature(
+      data_reduction_proxy::features::kDataReductionProxyBrotliHoldback);
+
+  Init(USE_SECURE_PROXY, true /* enable_brotli_globally */);
+
+  ReadBrotliFile();
+
+  std::string response_headers =
+      "HTTP/1.1 200 OK\r\n"
+      "Content-Length: 140\r\n"
+      "Via: 1.1 Chrome-Compression-Proxy\r\n"
+      "Chrome-Proxy: ofcl=200\r\n"
+      "Cache-Control: max-age=1200\r\n"
+      "Vary: accept-encoding\r\n";
+  response_headers += "\r\n";
+
+  // Use secure sockets when fetching the request since Brotli is only enabled
+  // for secure connections.
+  FetchURLRequestAndVerifyBrotli(nullptr, response_headers, false, false);
+}
+
 // Test that Brotli is not added to the accept-encoding header when the request
 // is fetched from an insecure proxy.
 TEST_F(DataReductionProxyNetworkDelegateTest,
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
index 75e628b..e793bcf0 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.cc
@@ -50,5 +50,11 @@
     "DataSaverSiteBreakdownUsingPageLoadMetrics",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+// If enabled, "br" is not added to the accept-encoding header. This effectively
+// disables the use of Brotli on the connection from Chrome to secure
+// HTTPS data saver proxies.
+const base::Feature kDataReductionProxyBrotliHoldback{
+    "DataReductionProxyBrotliHoldback", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
index 6682513..3f2c48d 100644
--- a/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
+++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_features.h
@@ -17,6 +17,7 @@
 extern const base::Feature kDataReductionProxyRobustConnection;
 extern const base::Feature kDogfood;
 extern const base::Feature kDataSaverSiteBreakdownUsingPageLoadMetrics;
+extern const base::Feature kDataReductionProxyBrotliHoldback;
 
 }  // namespace features
 }  // namespace data_reduction_proxy
diff --git a/components/download/internal/common/download_file_impl.cc b/components/download/internal/common/download_file_impl.cc
index 6a996e2..f24872f2 100644
--- a/components/download/internal/common/download_file_impl.cc
+++ b/components/download/internal/common/download_file_impl.cc
@@ -553,7 +553,6 @@
 
 void DownloadFileImpl::OnStreamCompleted(SourceStream* source_stream) {
   DownloadInterruptReason reason = HandleStreamCompletionStatus(source_stream);
-
   SendUpdate();
 
   NotifyObserver(source_stream, reason, InputStream::COMPLETE, false);
diff --git a/components/exo/buffer.cc b/components/exo/buffer.cc
index 42647b5..146019d 100644
--- a/components/exo/buffer.cc
+++ b/components/exo/buffer.cc
@@ -43,11 +43,6 @@
 
 GLenum GLInternalFormat(gfx::BufferFormat format) {
   const GLenum kGLInternalFormats[] = {
-      GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD,  // ATC
-      GL_COMPRESSED_RGB_S3TC_DXT1_EXT,     // ATCIA
-      GL_COMPRESSED_RGB_S3TC_DXT1_EXT,     // DXT1
-      GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,    // DXT5
-      GL_ETC1_RGB8_OES,                    // ETC1
       GL_R8_EXT,                           // R_8
       GL_R16_EXT,                          // R_16
       GL_RG8_EXT,                          // RG_88
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc
index 9c552a42..48c477b5 100644
--- a/components/exo/client_controlled_shell_surface.cc
+++ b/components/exo/client_controlled_shell_surface.cc
@@ -964,8 +964,11 @@
           .work_area();
 
   ash::wm::WindowState* window_state = GetWindowState();
-  if (window_state->IsMaximizedOrFullscreenOrPinned() &&
-      work_area.width() != geometry().width()) {
+  bool enable_wide_frame = GetFrameView()->visible() &&
+                           window_state->IsMaximizedOrFullscreenOrPinned() &&
+                           work_area.width() != geometry().width();
+
+  if (enable_wide_frame) {
     if (!wide_frame_) {
       wide_frame_ = std::make_unique<ash::WideFrameView>(widget_);
       ash::ImmersiveFullscreenController::EnableForWidget(widget_, false);
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index de276fa..810155d9 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1546,11 +1546,17 @@
   surface->Commit();
   EXPECT_TRUE(wide_frame->header_view()->in_immersive_mode());
 
+  // Switching to NONE means no frame so it should delete wide frame.
   surface->SetFrame(SurfaceFrameType::NONE);
   surface->Commit();
-  EXPECT_FALSE(wide_frame->header_view()->in_immersive_mode());
-
-  EXPECT_EQ(custom_targeter, window->targeter());
+  EXPECT_FALSE(shell_surface->wide_frame_for_test());
+  {
+    ui::MouseEvent event(ui::ET_MOUSE_MOVED, mouse_location, mouse_location,
+                         ui::EventTimeForNow(), 0, 0);
+    target =
+        static_cast<aura::Window*>(targeter.FindTargetForEvent(root, &event));
+  }
+  EXPECT_NE(surface->window(), target);
 
   // Unmaximize it and the frame should be normal.
   shell_surface->SetRestored();
diff --git a/components/invalidation/impl/non_blocking_invalidator_unittest.cc b/components/invalidation/impl/non_blocking_invalidator_unittest.cc
index 8cff019a..4ae9e028d0 100644
--- a/components/invalidation/impl/non_blocking_invalidator_unittest.cc
+++ b/components/invalidation/impl/non_blocking_invalidator_unittest.cc
@@ -18,6 +18,7 @@
 #include "google/cacheinvalidation/types.pb.h"
 #include "jingle/notifier/base/fake_base_task.h"
 #include "net/url_request/url_request_test_util.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace syncer {
@@ -43,6 +44,8 @@
         new net::TestURLRequestContextGetter(io_thread_.task_runner());
     notifier::NotifierOptions notifier_options;
     notifier_options.request_context_getter = request_context_getter_;
+    notifier_options.network_connection_tracker =
+        network::TestNetworkConnectionTracker::GetInstance();
     NetworkChannelCreator network_channel_creator =
         NonBlockingInvalidator::MakePushClientChannelCreator(notifier_options);
     invalidator_.reset(
diff --git a/components/invalidation/impl/p2p_invalidation_service.cc b/components/invalidation/impl/p2p_invalidation_service.cc
index 40d16d9..48607d73 100644
--- a/components/invalidation/impl/p2p_invalidation_service.cc
+++ b/components/invalidation/impl/p2p_invalidation_service.cc
@@ -21,10 +21,12 @@
 
 P2PInvalidationService::P2PInvalidationService(
     const scoped_refptr<net::URLRequestContextGetter>& request_context,
+    network::NetworkConnectionTracker* network_connection_tracker,
     syncer::P2PNotificationTarget notification_target) {
   notifier::NotifierOptions notifier_options =
       ParseNotifierOptions(*base::CommandLine::ForCurrentProcess());
   notifier_options.request_context_getter = request_context;
+  notifier_options.network_connection_tracker = network_connection_tracker;
   invalidator_id_ = GenerateInvalidatorClientId();
   invalidator_.reset(new syncer::P2PInvalidator(
           notifier::PushClient::CreateDefault(notifier_options),
diff --git a/components/invalidation/impl/p2p_invalidation_service.h b/components/invalidation/impl/p2p_invalidation_service.h
index 8bb39a6a..5b0c34b 100644
--- a/components/invalidation/impl/p2p_invalidation_service.h
+++ b/components/invalidation/impl/p2p_invalidation_service.h
@@ -19,6 +19,10 @@
 class URLRequestContextGetter;
 }
 
+namespace network {
+class NetworkConnectionTracker;
+}
+
 namespace syncer {
 class P2PInvalidator;
 }
@@ -34,6 +38,7 @@
  public:
   P2PInvalidationService(
       const scoped_refptr<net::URLRequestContextGetter>& request_context,
+      network::NetworkConnectionTracker* network_connection_tracker,
       syncer::P2PNotificationTarget notification_target);
   ~P2PInvalidationService() override;
 
diff --git a/components/invalidation/impl/ticl_invalidation_service.cc b/components/invalidation/impl/ticl_invalidation_service.cc
index b8ab8995..e83bccd 100644
--- a/components/invalidation/impl/ticl_invalidation_service.cc
+++ b/components/invalidation/impl/ticl_invalidation_service.cc
@@ -356,6 +356,7 @@
     case PUSH_CLIENT_CHANNEL: {
       notifier::NotifierOptions options =
           ParseNotifierOptions(*base::CommandLine::ForCurrentProcess());
+      options.network_connection_tracker = network_connection_tracker_;
       options.request_context_getter = request_context_;
       options.auth_mechanism = "X-OAUTH2";
       network_channel_options_.SetString("Options.HostPort",
diff --git a/components/metrics/call_stack_profile_metrics_provider.cc b/components/metrics/call_stack_profile_metrics_provider.cc
index 5b2993a..3001801 100644
--- a/components/metrics/call_stack_profile_metrics_provider.cc
+++ b/components/metrics/call_stack_profile_metrics_provider.cc
@@ -26,43 +26,16 @@
 // profile representation.
 const size_t kMaxPendingProfiles = 1250;
 
-// ProfileState --------------------------------------------------------------
-
-// A set of profiles and the start time of the collection associated with them.
-struct ProfileState {
-  ProfileState(base::TimeTicks start_timestamp, SampledProfile profile);
-  ProfileState(base::TimeTicks start_timestamp, std::string serialized_profile);
-  ProfileState(ProfileState&&);
-  ProfileState& operator=(ProfileState&&);
-
-  // The time at which the profile collection was started.
-  base::TimeTicks start_timestamp;
-
-  // A serialized SampledProfile. The profile for this instance will be
-  // contained in exactly one of |serialized_profile| or |profile|. If
-  // |serialized_profile| is empty, the profile will be in |profile|.
-  std::string serialized_profile;
-
-  // The call stack profile message collected by the profiler.
-  SampledProfile profile;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ProfileState);
-};
-
-ProfileState::ProfileState(base::TimeTicks start_timestamp,
-                           SampledProfile profile)
-    : start_timestamp(start_timestamp), profile(std::move(profile)) {}
-
-ProfileState::ProfileState(base::TimeTicks start_timestamp,
-                           std::string serialized_profile)
-    : start_timestamp(start_timestamp),
-      serialized_profile(std::move(serialized_profile)) {}
-
-ProfileState::ProfileState(ProfileState&&) = default;
-
-// Some versions of GCC need this for push_back to work with std::move.
-ProfileState& ProfileState::operator=(ProfileState&&) = default;
+// Cap the number of pending unserialized profiles to avoid excessive memory
+// usage when profile uploads are delayed (e.g., due to being offline). When the
+// number of pending unserialized profiles exceeds this cap, serialize all
+// additional unserialized profiles to save memory. Since profile serialization
+// and deserialization (required later for uploads) are expensive, we choose 250
+// as the capacity to balance speed and memory. 250 unserialized profiles
+// corresponds to 16MB of storage.
+// TODO(chengx): Remove this threshold after moving to a more memory-efficient
+// profile representation.
+constexpr size_t kMaxPendingUnserializedProfiles = 250;
 
 // PendingProfiles ------------------------------------------------------------
 
@@ -78,17 +51,31 @@
  public:
   static PendingProfiles* GetInstance();
 
-  // Retrieves all the pending profiles.
-  std::vector<ProfileState> Retrieve();
+  // Retrieves all the pending unserialized profiles.
+  std::vector<SampledProfile> RetrieveUnserializedProfiles();
 
-  // Enables the collection of profiles by CollectProfilesIfCollectionEnabled if
-  // |enabled| is true. Otherwise, clears current profiles and ignores profiles
-  // provided to future invocations of CollectProfilesIfCollectionEnabled.
+  // Retrieves all the pending serialized profiles.
+  std::vector<std::string> RetrieveSerializedProfiles();
+
+  // Enables the collection of profiles by CollectUnserializedProfile or
+  // CollectSerializedProfile if |enabled| is true. Otherwise, clears current
+  // profiles and ignores profiles provided to future invocations of
+  // CollectUnserializedProfile or CollectSerializedProfile.
   void SetCollectionEnabled(bool enabled);
 
-  // Adds |profile| to the list of profiles if collection is enabled; it is
-  // not const& because it must be passed with std::move.
-  void CollectProfilesIfCollectionEnabled(ProfileState profile);
+  // Returns true if collection is enabled for a given profile based on its
+  // |profile_start_time|.
+  bool IsCollectionEnabledForProfile(base::TimeTicks profile_start_time) const;
+
+  // Collects |profile|. It may be stored as it is, or in a serialized form, or
+  // ignored, depending on the pre-defined storage capacity; it is not const&
+  // because it must be passed with std::move.
+  void CollectUnserializedProfile(SampledProfile profile);
+
+  // Collects |serialized_profile|. It may be ignored depending on the
+  // pre-defined storage capacity; it is not const& because it must be passed
+  // with std::move.
+  void CollectSerializedProfile(std::string serialized_profile);
 
   // Allows testing against the initial state multiple times.
   void ResetToDefaultStateForTesting();
@@ -101,8 +88,9 @@
 
   mutable base::Lock lock_;
 
-  // If true, profiles provided to CollectProfilesIfCollectionEnabled should be
-  // collected. Otherwise they will be ignored.
+  // If true, profiles provided to CollectUnserializedProfile or
+  // CollectSerializedProfile should be collected. Otherwise they will be
+  // ignored.
   bool collection_enabled_;
 
   // The last time collection was disabled. Used to determine if collection was
@@ -113,8 +101,11 @@
   // enabled at any point since a profile was started.
   base::TimeTicks last_collection_enable_time_;
 
-  // The set of completed profiles that should be reported.
-  std::vector<ProfileState> profiles_;
+  // The set of completed unserialized profiles that should be reported.
+  std::vector<SampledProfile> unserialized_profiles_;
+
+  // The set of completed serialized profiles that should be reported.
+  std::vector<std::string> serialized_profiles_;
 
   DISALLOW_COPY_AND_ASSIGN(PendingProfiles);
 };
@@ -126,9 +117,14 @@
   return instance.get();
 }
 
-std::vector<ProfileState> PendingProfiles::Retrieve() {
+std::vector<SampledProfile> PendingProfiles::RetrieveUnserializedProfiles() {
   base::AutoLock scoped_lock(lock_);
-  return std::move(profiles_);
+  return std::move(unserialized_profiles_);
+}
+
+std::vector<std::string> PendingProfiles::RetrieveSerializedProfiles() {
+  base::AutoLock scoped_lock(lock_);
+  return std::move(serialized_profiles_);
 }
 
 void PendingProfiles::SetCollectionEnabled(bool enabled) {
@@ -137,38 +133,68 @@
   collection_enabled_ = enabled;
 
   if (!collection_enabled_) {
-    profiles_.clear();
+    unserialized_profiles_.clear();
+    serialized_profiles_.clear();
     last_collection_disable_time_ = base::TimeTicks::Now();
   } else {
     last_collection_enable_time_ = base::TimeTicks::Now();
   }
 }
 
-void PendingProfiles::CollectProfilesIfCollectionEnabled(ProfileState profile) {
+bool PendingProfiles::IsCollectionEnabledForProfile(
+    base::TimeTicks profile_start_time) const {
   base::AutoLock scoped_lock(lock_);
 
-  // Scenario 1: stop collection if it is disabled.
+  // Scenario 1: return false if collection is disabled.
   if (!collection_enabled_)
-    return;
+    return false;
 
-  // Scenario 2: stop collection if it is disabled after the start of collection
-  // for this profile.
+  // Scenario 2: return false if collection is disabled after the start of
+  // collection for this profile.
   if (!last_collection_disable_time_.is_null() &&
-      last_collection_disable_time_ >= profile.start_timestamp) {
-    return;
+      last_collection_disable_time_ >= profile_start_time) {
+    return false;
   }
 
-  // Scenario 3: stop collection if it is disabled before the start of
+  // Scenario 3: return false if collection is disabled before the start of
   // collection and re-enabled after the start. Note that this is different from
   // scenario 1 where re-enabling never happens.
   if (!last_collection_disable_time_.is_null() &&
       !last_collection_enable_time_.is_null() &&
-      last_collection_enable_time_ >= profile.start_timestamp) {
+      last_collection_enable_time_ >= profile_start_time) {
+    return false;
+  }
+
+  return true;
+}
+
+void PendingProfiles::CollectUnserializedProfile(SampledProfile profile) {
+  base::AutoLock scoped_lock(lock_);
+
+  // Store the unserialized profile directly if we are under the capacity for
+  // unserialized profiles.
+  if (unserialized_profiles_.size() < kMaxPendingUnserializedProfiles) {
+    unserialized_profiles_.push_back(std::move(profile));
     return;
   }
 
-  if (profiles_.size() < kMaxPendingProfiles)
-    profiles_.push_back(std::move(profile));
+  // If there is no room for unserialized profiles but there is still room for
+  // serialized profiles, convert the unserialized profile to serialized form.
+  if ((unserialized_profiles_.size() + serialized_profiles_.size()) <
+      kMaxPendingProfiles) {
+    std::string serialized_profile;
+    profile.SerializeToString(&serialized_profile);
+    serialized_profiles_.push_back(std::move(serialized_profile));
+  }
+}
+
+void PendingProfiles::CollectSerializedProfile(std::string serialized_profile) {
+  base::AutoLock scoped_lock(lock_);
+
+  if ((unserialized_profiles_.size() + serialized_profiles_.size()) <
+      kMaxPendingProfiles) {
+    serialized_profiles_.push_back(std::move(serialized_profile));
+  }
 }
 
 void PendingProfiles::ResetToDefaultStateForTesting() {
@@ -177,7 +203,8 @@
   collection_enabled_ = true;
   last_collection_disable_time_ = base::TimeTicks();
   last_collection_enable_time_ = base::TimeTicks();
-  profiles_.clear();
+  unserialized_profiles_.clear();
+  serialized_profiles_.clear();
 }
 
 // |collection_enabled_| is initialized to true to collect any profiles that are
@@ -202,19 +229,26 @@
 void CallStackProfileMetricsProvider::ReceiveProfile(
     base::TimeTicks profile_start_time,
     SampledProfile profile) {
-  PendingProfiles::GetInstance()->CollectProfilesIfCollectionEnabled(
-      ProfileState(profile_start_time, std::move(profile)));
-  // TODO(wittman): Check if we have a lot of raw profiles outstanding
-  // (e.g. because the client is offline) and if so, convert them to serialized
-  // form to minimize memory usage.
+  if (!PendingProfiles::GetInstance()->IsCollectionEnabledForProfile(
+          profile_start_time)) {
+    return;
+  }
+
+  PendingProfiles::GetInstance()->CollectUnserializedProfile(
+      std::move(profile));
 }
 
 // static
 void CallStackProfileMetricsProvider::ReceiveSerializedProfile(
     base::TimeTicks profile_start_time,
-    std::string serialized_sampled_profile) {
-  PendingProfiles::GetInstance()->CollectProfilesIfCollectionEnabled(
-      ProfileState(profile_start_time, std::move(serialized_sampled_profile)));
+    std::string serialized_profile) {
+  if (!PendingProfiles::GetInstance()->IsCollectionEnabledForProfile(
+          profile_start_time)) {
+    return;
+  }
+
+  PendingProfiles::GetInstance()->CollectSerializedProfile(
+      std::move(serialized_profile));
 }
 
 void CallStackProfileMetricsProvider::OnRecordingEnabled() {
@@ -228,21 +262,23 @@
 
 void CallStackProfileMetricsProvider::ProvideCurrentSessionData(
     ChromeUserMetricsExtension* uma_proto) {
-  std::vector<ProfileState> pending_profiles =
-      PendingProfiles::GetInstance()->Retrieve();
+  std::vector<SampledProfile> unserialized_profiles =
+      PendingProfiles::GetInstance()->RetrieveUnserializedProfiles();
+
+  std::vector<std::string> serialized_profiles =
+      PendingProfiles::GetInstance()->RetrieveSerializedProfiles();
 
   DCHECK(base::FeatureList::IsEnabled(kEnableReporting) ||
-         pending_profiles.empty());
+         (unserialized_profiles.empty() && serialized_profiles.empty()));
 
-  for (const auto& profile_state : pending_profiles) {
-    if (!profile_state.serialized_profile.empty()) {
-      SampledProfile profile;
-      if (profile.ParseFromArray(profile_state.serialized_profile.data(),
-                                 profile_state.serialized_profile.size())) {
-        *uma_proto->add_sampled_profile() = std::move(profile);
-      }
-    } else {
-      *uma_proto->add_sampled_profile() = std::move(profile_state.profile);
+  for (auto& profile : unserialized_profiles)
+    *uma_proto->add_sampled_profile() = std::move(profile);
+
+  for (auto& serialized_profile : serialized_profiles) {
+    SampledProfile profile;
+    if (profile.ParseFromArray(serialized_profile.data(),
+                               serialized_profile.size())) {
+      *uma_proto->add_sampled_profile() = std::move(profile);
     }
   }
 }
diff --git a/components/metrics/call_stack_profile_metrics_provider_unittest.cc b/components/metrics/call_stack_profile_metrics_provider_unittest.cc
index 5869883..690b42c 100644
--- a/components/metrics/call_stack_profile_metrics_provider_unittest.cc
+++ b/components/metrics/call_stack_profile_metrics_provider_unittest.cc
@@ -73,6 +73,99 @@
             uma_proto.sampled_profile(0).trigger_event());
 }
 
+// Checks that both the unserialized and serialized pending profiles are
+// encoded in the session data.
+TEST_F(CallStackProfileMetricsProviderTest,
+       ProvideCurrentSessionDataUnserializedAndSerialized) {
+  CallStackProfileMetricsProvider provider;
+  provider.OnRecordingEnabled();
+
+  // Receive an unserialized profile.
+  SampledProfile profile;
+  profile.set_trigger_event(SampledProfile::PROCESS_STARTUP);
+  CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
+                                                  std::move(profile));
+
+  // Receive a serialized profile.
+  std::string contents;
+  {
+    SampledProfile profile;
+    profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
+    profile.SerializeToString(&contents);
+  }
+  CallStackProfileMetricsProvider::ReceiveSerializedProfile(
+      base::TimeTicks::Now(), std::move(contents));
+
+  ChromeUserMetricsExtension uma_proto;
+  provider.ProvideCurrentSessionData(&uma_proto);
+  ASSERT_EQ(2, uma_proto.sampled_profile().size());
+  EXPECT_EQ(SampledProfile::PROCESS_STARTUP,
+            uma_proto.sampled_profile(0).trigger_event());
+  EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION,
+            uma_proto.sampled_profile(1).trigger_event());
+}
+
+// Checks that the unserialized pending profiles whose number exceeds the
+// associated cap are still encoded in the session data.
+TEST_F(CallStackProfileMetricsProviderTest,
+       ProvideCurrentSessionDataExceedUnserializedCap) {
+  // The value must be consistent with that in
+  // call_stack_profile_metrics_provider.cc so that this test is meaningful.
+  constexpr int kMaxPendingUnserializedProfiles = 250;
+
+  CallStackProfileMetricsProvider provider;
+  provider.OnRecordingEnabled();
+
+  // Receive (kMaxPendingUnserializedProfiles + 1) unserialized profiles.
+  for (int i = 0; i < kMaxPendingUnserializedProfiles + 1; ++i) {
+    SampledProfile profile;
+    profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
+    CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
+                                                    std::move(profile));
+  }
+
+  ChromeUserMetricsExtension uma_proto;
+  provider.ProvideCurrentSessionData(&uma_proto);
+
+  ASSERT_EQ(kMaxPendingUnserializedProfiles + 1,
+            uma_proto.sampled_profile().size());
+  for (int i = 0; i < kMaxPendingUnserializedProfiles + 1; ++i) {
+    EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION,
+              uma_proto.sampled_profile(i).trigger_event());
+  }
+}
+
+// Checks that the pending profiles above the total cap are dropped therefore
+// not encoded in the session data.
+TEST_F(CallStackProfileMetricsProviderTest,
+       ProvideCurrentSessionDataExceedTotalCap) {
+  // The value must be consistent with that in
+  // call_stack_profile_metrics_provider.cc so that this test is meaningful.
+  const int kMaxPendingProfiles = 1250;
+
+  CallStackProfileMetricsProvider provider;
+  provider.OnRecordingEnabled();
+
+  // Receive (kMaxPendingProfiles + 1) profiles.
+  for (int i = 0; i < kMaxPendingProfiles + 1; ++i) {
+    SampledProfile profile;
+    profile.set_trigger_event(SampledProfile::PERIODIC_COLLECTION);
+    CallStackProfileMetricsProvider::ReceiveProfile(base::TimeTicks::Now(),
+                                                    std::move(profile));
+  }
+
+  ChromeUserMetricsExtension uma_proto;
+  provider.ProvideCurrentSessionData(&uma_proto);
+
+  // Only kMaxPendingProfiles profiles are encoded, with the additional one
+  // dropped.
+  ASSERT_EQ(kMaxPendingProfiles, uma_proto.sampled_profile().size());
+  for (int i = 0; i < kMaxPendingProfiles; ++i) {
+    EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION,
+              uma_proto.sampled_profile(i).trigger_event());
+  }
+}
+
 // Checks that the pending profile is provided to ProvideCurrentSessionData
 // when collected before CallStackProfileMetricsProvider is instantiated.
 TEST_F(CallStackProfileMetricsProviderTest,
diff --git a/components/neterror/resources/images/file.svg b/components/neterror/resources/images/file.svg
new file mode 100644
index 0000000..64746c3
--- /dev/null
+++ b/components/neterror/resources/images/file.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z" fill="#3C4043" /></svg>
\ No newline at end of file
diff --git a/components/neterror/resources/images/offline_pin.svg b/components/neterror/resources/images/offline_pin.svg
new file mode 100644
index 0000000..d21fe5b
--- /dev/null
+++ b/components/neterror/resources/images/offline_pin.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="24" height="24">
+    <defs>
+        <path id="a" d="M0 0h24v24H0V0z"/>
+    </defs>
+    <clipPath id="b">
+        <use xlink:href="#a" overflow="visible"/>
+    </clipPath>
+    <path clip-path="url(#b)" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm5 16H7v-2h10v2zm-6.7-4L7 10.7l1.4-1.4 1.9 1.9 5.3-5.3L17 7.3 10.3 14z" fill="rgb(154, 160, 166)"/>
+</svg>
diff --git a/components/neterror/resources/neterror.css b/components/neterror/resources/neterror.css
index 476e987..b8158a4 100644
--- a/components/neterror/resources/neterror.css
+++ b/components/neterror/resources/neterror.css
@@ -323,7 +323,8 @@
 }
 
 #download-link, #download-link-clicked {
-  margin-bottom: 15px;
+  margin-bottom: 30px;
+  margin-top: 30px;
 }
 
 #download-link-clicked {
@@ -342,57 +343,201 @@
   opacity: 0;
 }
 
-.offline-content-suggestion-image {
-  height: 35vw;
-  line-height: 0;
-  width: 35vw;
-  flex-basis: 35vw;
-  flex-grow: 0;
+.offline-content-list-title {
+  color: rgb(95, 99, 104);
+  font-size: .8em;
+  line-height: 1;
+  margin-bottom: .8em;
+}
+
+#offline-content-suggestions {
+  margin-inline-start: -5%;
+  width: 110%;
+}
+
+/* The selectors below adjust the "overflow" of the suggestion cards contents
+ * based on the same screen size based strategy used for the main frame, which
+ * is applied by the `interstitial-wrapper` class. */
+@media (max-width: 700px) {
+  #offline-content-suggestions {
+    margin-inline-start: -5%;
+    width: 110%;
+  }
+}
+@media (max-width: 420px)  {
+  #offline-content-suggestions {
+    margin-inline-start: -2.5%;
+    width: 105%;
+  }
+}
+@media (max-width: 420px) and (orientation: portrait),
+       (max-height: 560px) {
+  #offline-content-suggestions {
+    margin-inline-start: -12px;
+    width: calc(100% + 24px);
+  }
+}
+
+.suggestion-with-image .offline-content-suggestion-visual {
+  flex-basis: 8.2em;
   flex-shrink: 0;
 }
 
-.offline-content-suggestion-image > img {
-  border-bottom-left-radius: 15px;
-  border-top-left-radius: 15px;
-  height: 35vw;
-  line-height: 0;
-  width: 35vw;
+.suggestion-with-image .offline-content-suggestion-visual > img {
+  height: 100%;
+  width: 100%;
+}
+
+#offline-content-list:not(.is-rtl) .suggestion-with-image
+.offline-content-suggestion-visual > img {
+  border-bottom-right-radius: 8px;
+  border-top-right-radius: 8px;
+}
+
+#offline-content-list.is-rtl .suggestion-with-image
+.offline-content-suggestion-visual > img {
+  border-bottom-left-radius: 8px;
+  border-top-left-radius: 8px;
+}
+
+.suggestion-with-icon .offline-content-suggestion-visual {
+  align-items: center;
+  display: flex;
+  justify-content: center;
+  min-height: 4.2em;
+  min-width: 4.2em;
+}
+
+.suggestion-with-icon .offline-content-suggestion-visual > div {
+  align-items: center;
+  background-color: rgb(241, 243, 244);
+  border-radius: 50%;
+  display: flex;
+  height: 2.3em;
+  justify-content: center;
+  width: 2.3em;
+}
+
+.suggestion-with-icon .offline-content-suggestion-visual > div > img {
+  height: 1.45em;
+  width: 1.45em;
+}
+
+.image-video {
+  content: url(images/video.svg);
+}
+
+.image-music-note {
+  content: url(images/music-note.svg);
+}
+
+.image-earth {
+  content: url(images/earth.svg);
+}
+
+.image-file {
+  content: url(images/file.svg);
+}
+
+.offline-content-suggestion-texts {
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  line-height: 1.3;
+  padding: .9em;
+  width: 100%;
 }
 
 .offline-content-suggestion-title {
   -webkit-box-orient: vertical;
   -webkit-line-clamp: 3;
+  color: rgb(32, 33, 36);
   display: -webkit-box;
-  margin: 5%;
-  max-height: 65px;
+  font-size: 1.1em;
   overflow: hidden;
   text-overflow: ellipsis;
 }
 
-.offline-content-suggestion-freshness, .offline-content-suggestion-attribution {
-  color: #646464;
-  display: inline-block;
-  font-size: small;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.offline-content-suggestion-attribution {
-  margin-left: 5%;
-  max-width: 35%;
-  overflow: hidden;
-  white-space: nowrap;
-}
-
 div.offline-content-suggestion {
-  background-color: rgb(241, 243, 244);
-  border-radius: 15px;
+  align-items: stretch;
+  border-color: rgb(218, 220, 224);
+  border-radius: 8px;
+  border-style: solid;
+  border-width: 1px;
   display: flex;
-  margin-bottom: 5%;
-  margin-left: 0;
-  margin-right: 0;
-  margin-top: 5%;
+  justify-content: space-between;
+  margin-bottom: .8em;
+}
+
+.suggestion-with-image {
+  flex-direction: row;
+  height: 8.2em;
+  max-height: 8.2em;
+}
+
+.suggestion-with-icon {
+  flex-direction: row-reverse;
+  height: 4.2em;
+  max-height: 4.2em;
+}
+
+.suggestion-with-icon .offline-content-suggestion-title {
+  -webkit-line-clamp: 1;
+  word-break: break-all;
+}
+
+.suggestion-with-icon .offline-content-suggestion-texts {
+  padding-inline-start: 0px;
+}
+
+.offline-content-suggestion-attribution-freshness {
+  color: rgb(95, 99, 104);
+  display: flex;
+  font-size: .8em;
+}
+
+.offline-content-suggestion-attribution {
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 1;
+  display: -webkit-box;
+  flex-shrink: 1;
+  overflow-wrap: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  word-break: break-all;
+}
+
+.offline-content-suggestion-freshness:before {
+  content: '-';
+  display: inline-block;
+  flex-shrink: 0;
+  margin-inline-end: .1em;
+  margin-inline-start: .1em;
+}
+
+.no-attribution .offline-content-suggestion-freshness:before {
+  display: none;
+}
+
+.offline-content-suggestion-freshness {
+  flex-shrink: 0;
+}
+
+.suggestion-with-image .offline-content-suggestion-pin-spacer {
+  flex-shrink: 1;
+  flex-grow: 100;
+}
+
+.suggestion-with-image .offline-content-suggestion-pin {
+  content: url(images/offline_pin.svg);
+  flex-shrink: 0;
+  height: 1.4em;
+  margin-inline-start: .4em;
+  width: 1.4em;
+}
+
+.offline-content-list-action {
+  text-align: center;
 }
 
 #offline-content-summary {
diff --git a/components/neterror/resources/neterror.html b/components/neterror/resources/neterror.html
index 60efe5a..96f398c 100644
--- a/components/neterror/resources/neterror.html
+++ b/components/neterror/resources/neterror.html
@@ -62,7 +62,18 @@
             </div>
           </div>
         </div>
-        <div id="offline-content-list" hidden></div>
+        <div id="offline-content-list" hidden>
+          <webview>
+            <div class="offline-content-list-title" jsselect="offlineContentList"
+                jscontent="title"></div>
+            <div id="offline-content-suggestions"></div>
+            <div class="offline-content-list-action">
+              <a class="link-button" onclick="launchDownloadsPage()" 
+                  jsselect="offlineContentList" jscontent="actionText">
+              </a>
+            </div>
+          </webview>
+        </div>
         <div id="offline-content-summary" onclick="launchDownloadsPage()" hidden>
           <div class="offline-content-summary-images">
             <div class="offline-content-summary-image-truncate">
diff --git a/components/neterror/resources/neterror.js b/components/neterror/resources/neterror.js
index c0c4e02..206592e 100644
--- a/components/neterror/resources/neterror.js
+++ b/components/neterror/resources/neterror.js
@@ -164,30 +164,6 @@
       .classList.toggle(HIDDEN_CLASS);
 }
 
-function getSuggestedContentDiv(item) {
-  var visual = '';
-    if (item.thumbnail_data_uri) {
-      // html_inline.py will try to replace src attributes with data URIs using
-      // a simple regex. The following is obfuscated slightly to avoid that.
-      var src = 'src';
-      visual = `<img ${src}="${item.thumbnail_data_uri}">`;
-    }
-    return `
-<div class="offline-content-suggestion"
-  onclick="launchOfflineItem('${item.ID}', '${item.name_space}')">
-  <div class="offline-content-suggestion-image">${visual}</div>
-  <div>
-    <div class="offline-content-suggestion-title">${item.title}</div>
-    <span class="offline-content-suggestion-attribution">${
-                                                           item.attribution
-                                                         }</span>
-    <span class="offline-content-suggestion-freshness">${
-                                                         item.date_modified
-                                                       }</span>
-  </div>
-</div>`;
-}
-
 function launchOfflineItem(itemID, name_space) {
   errorPageController.launchOfflineItem(itemID, name_space);
 }
@@ -204,28 +180,80 @@
   document.getElementById('offline-content-summary').hidden = false;
 }
 
+function getIconForSuggestedItem(item) {
+  // Note: |item.content_type| contains the enum values from
+  // chrome::mojom::AvailableContentType.
+  switch (item.content_type) {
+    case 1:  // kVideo
+      return 'image-video';
+    case 2:  // kAudio
+      return 'image-music-note';
+    case 0:  // kPrefetchedUnopenedPage
+    case 3:  // kOtherPage
+      return 'image-earth';
+  }
+  return 'image-file';
+}
+
+function getSuggestedContentDiv(item) {
+  // Note: See AvailableContentToValue in available_offline_content_helper.cc
+  // for the data contained in an |item|.
+  var visual = '';
+  var extraContainerClasses = [];
+  // html_inline.py will try to replace src attributes with data URIs using a
+  // simple regex. The following is obfuscated slightly to avoid that.
+  var src = 'src';
+  if (item.thumbnail_data_uri) {
+    extraContainerClasses.push('suggestion-with-image');
+    visual = `<img ${src}="${item.thumbnail_data_uri}">`;
+  } else {
+    extraContainerClasses.push('suggestion-with-icon');
+    iconClass = getIconForSuggestedItem(item);
+    visual = `<div><img class="${iconClass}"></div>`;
+  }
+
+  if (!item.attribution)
+    extraContainerClasses.push('no-attribution');
+
+  return `
+  <div class="offline-content-suggestion ${extraContainerClasses.join(' ')}"
+    onclick="launchOfflineItem('${item.ID}', '${item.name_space}')">
+      <div class="offline-content-suggestion-texts">
+        <div class="offline-content-suggestion-title">
+          ${item.title}
+        </div>
+        <div class="offline-content-suggestion-attribution-freshness">
+          <div class="offline-content-suggestion-attribution">
+            ${item.attribution}
+          </div>
+          <div class="offline-content-suggestion-freshness">
+            ${item.date_modified}
+          </div>
+          <div class="offline-content-suggestion-pin-spacer"></div>
+          <div class="offline-content-suggestion-pin"></div>
+        </div>
+      </div>
+      <div class="offline-content-suggestion-visual">
+        ${visual}
+      </div>
+  </div>`;
+}
+
 // Populates a list of suggested offline content.
-// TODO(https://crbug.com/852872): Finish implementing offline content list UI.
-function offlineContentAvailable(content) {
-  if (!content || !loadTimeData.valueExists('offlineContentList'))
+function offlineContentAvailable(suggestions) {
+  if (!suggestions || !loadTimeData.valueExists('offlineContentList'))
     return;
 
-  var contentTitle = loadTimeData.getValue('offlineContentList').title;
-  var contentOpenAllButton =
-      loadTimeData.getValue('offlineContentList').actionText;
   var suggestionsHTML = [];
-  suggestionsHTML.push(`<p style="text-align: center;">${contentTitle}</p>`);
-  for (var c of content)
-    suggestionsHTML.push(getSuggestedContentDiv(c));
-  suggestionsHTML.push(`
-<div>
-  <a class="link-button" onclick="launchDownloadsPage()">${
-                                                           contentOpenAllButton
-                                                         }</a>
-</div>`);
-  var offlineContentDiv = document.getElementById('offline-content-list');
-  offlineContentDiv.innerHTML = suggestionsHTML.join('\n');
-  offlineContentDiv.hidden = false;
+  for (var item of suggestions)
+    suggestionsHTML.push(getSuggestedContentDiv(item));
+  document.getElementById('offline-content-suggestions').innerHTML =
+      suggestionsHTML.join('\n');
+
+  var contentListElement = document.getElementById('offline-content-list')
+  contentListElement.hidden = false;
+  if (document.dir == 'rtl')
+    contentListElement.classList.add('is-rtl');
 }
 
 function onDocumentLoad() {
diff --git a/components/offline_items_collection/core/fail_state.h b/components/offline_items_collection/core/fail_state.h
index 5d615842..606a2b3 100644
--- a/components/offline_items_collection/core/fail_state.h
+++ b/components/offline_items_collection/core/fail_state.h
@@ -11,10 +11,119 @@
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.offline_items_collection
 enum class FailState {
   // Enum for reason OfflineItem failed to download.
-  NO_FAILURE,           // Download did not fail.
-  CANNOT_DOWNLOAD,      // Download cannot be downloaded.
+  NO_FAILURE,       // Download did not fail.
+  CANNOT_DOWNLOAD,  // Download cannot be downloaded. Deprecated, use detailed
+                    // states below.
   NETWORK_INSTABILITY,  // Download failed due to poor or unstable network
-                        // connection.
+                        // connection. Deprecated, use detailed states below.
+  // Generic file operation failure.
+  FILE_FAILED,
+
+  // The file cannot be accessed due to security restrictions.
+  FILE_ACCESS_DENIED,
+
+  // There is not enough room on the drive.
+  FILE_NO_SPACE,
+
+  // The directory or file name is too long.
+  FILE_NAME_TOO_LONG,
+
+  // The file is too large for the file system to handle.
+  FILE_TOO_LARGE,
+
+  // The file contains a virus.
+  FILE_VIRUS_INFECTED,
+
+  // The file was in use.
+  // Too many files are opened at once.
+  // We have run out of memory.
+  FILE_TRANSIENT_ERROR,
+
+  // The file was blocked due to local policy.
+  FILE_BLOCKED,
+
+  // An attempt to check the safety of the download failed due to unexpected
+  // reasons. See http://crbug.com/153212.
+  FILE_SECURITY_CHECK_FAILED,
+
+  // An attempt was made to seek past the end of a file in opening
+  // a file (as part of resuming a previously interrupted download).
+  FILE_TOO_SHORT,
+
+  // The partial file didn't match the expected hash.
+  FILE_HASH_MISMATCH,
+
+  // The source and the target of the download were the same.
+  FILE_SAME_AS_SOURCE,
+
+  // Network errors.
+
+  // Generic network failure.
+  NETWORK_FAILED,
+
+  // The network operation timed out.
+  NETWORK_TIMEOUT,
+
+  // The network connection has been lost.
+  NETWORK_DISCONNECTED,
+
+  // The server has gone down.
+  NETWORK_SERVER_DOWN,
+
+  // The network request was invalid. This may be due to the original URL or a
+  // redirected URL:
+  // - Having an unsupported scheme.
+  // - Being an invalid URL.
+  // - Being disallowed by policy.
+  NETWORK_INVALID_REQUEST,
+
+  // Server responses.
+
+  // The server indicates that the operation has failed (generic).
+  SERVER_FAILED,
+
+  // The server does not support range requests.
+  // Internal use only:  must restart from the beginning.
+  SERVER_NO_RANGE,
+
+  // The server does not have the requested data.
+  SERVER_BAD_CONTENT,
+
+  // Server didn't authorize access to resource.
+  SERVER_UNAUTHORIZED,
+
+  // Server certificate problem.
+  SERVER_CERT_PROBLEM,
+
+  // Server access forbidden.
+  SERVER_FORBIDDEN,
+
+  // Unexpected server response. This might indicate that the responding server
+  // may not be the intended server.
+  SERVER_UNREACHABLE,
+
+  // The server sent fewer bytes than the content-length header. It may indicate
+  // that the connection was closed prematurely, or the Content-Length header
+  // was
+  // invalid. The download is only interrupted if strong validators are present.
+  // Otherwise, it is treated as finished.
+  SERVER_CONTENT_LENGTH_MISMATCH,
+
+  // An unexpected cross-origin redirect happened.
+  SERVER_CROSS_ORIGIN_REDIRECT,
+
+  // User input.
+
+  // The user canceled the download.
+  USER_CANCELED,
+
+  // The user shut down the browser.
+  USER_SHUTDOWN,
+
+  // Crash.
+
+  // The browser crashed.
+  CRASH,
 };
 
 // Implemented for testing only. See test_support/offline_item_test_support.cc.
diff --git a/components/offline_items_collection/core/test_support/offline_item_test_support.cc b/components/offline_items_collection/core/test_support/offline_item_test_support.cc
index a45b381..ac71fbb 100644
--- a/components/offline_items_collection/core/test_support/offline_item_test_support.cc
+++ b/components/offline_items_collection/core/test_support/offline_item_test_support.cc
@@ -79,6 +79,64 @@
       return os << "CANNOT_DOWNLOAD";
     case FailState::NETWORK_INSTABILITY:
       return os << "NETWORK_INSTABILITY";
+    case FailState::FILE_FAILED:
+      return os << "FILE_FAILED";
+    case FailState::FILE_ACCESS_DENIED:
+      return os << "FILE_ACCESS_DENIED";
+    case FailState::FILE_NO_SPACE:
+      return os << "FILE_NO_SPACE";
+    case FailState::FILE_NAME_TOO_LONG:
+      return os << "FILE_NAME_TOO_LONG";
+    case FailState::FILE_TOO_LARGE:
+      return os << "FILE_TOO_LARGE";
+    case FailState::FILE_VIRUS_INFECTED:
+      return os << "FILE_VIRUS_INFECTED";
+    case FailState::FILE_TRANSIENT_ERROR:
+      return os << "FILE_TRANSIENT_ERROR";
+    case FailState::FILE_BLOCKED:
+      return os << "FILE_BLOCKED";
+    case FailState::FILE_SECURITY_CHECK_FAILED:
+      return os << "FILE_SECURITY_CHECK_FAILED";
+    case FailState::FILE_TOO_SHORT:
+      return os << "FILE_TOO_SHORT";
+    case FailState::FILE_HASH_MISMATCH:
+      return os << "FILE_HASH_MISMATCH";
+    case FailState::FILE_SAME_AS_SOURCE:
+      return os << "FILE_SAME_AS_SOURCE";
+    case FailState::NETWORK_FAILED:
+      return os << "NETWORK_FAILED";
+    case FailState::NETWORK_TIMEOUT:
+      return os << "NETWORK_TIMEOUT";
+    case FailState::NETWORK_DISCONNECTED:
+      return os << "NETWORK_DISCONNECTED";
+    case FailState::NETWORK_SERVER_DOWN:
+      return os << "NETWORK_SERVER_DOWN";
+    case FailState::NETWORK_INVALID_REQUEST:
+      return os << "NETWORK_INVALID_REQUEST";
+    case FailState::SERVER_FAILED:
+      return os << "SERVER_FAILED";
+    case FailState::SERVER_NO_RANGE:
+      return os << "SERVER_NO_RANGE";
+    case FailState::SERVER_BAD_CONTENT:
+      return os << "SERVER_BAD_CONTENT";
+    case FailState::SERVER_UNAUTHORIZED:
+      return os << "SERVER_UNAUTHORIZED";
+    case FailState::SERVER_CERT_PROBLEM:
+      return os << "SERVER_CERT_PROBLEM";
+    case FailState::SERVER_FORBIDDEN:
+      return os << "SERVER_FORBIDDEN";
+    case FailState::SERVER_UNREACHABLE:
+      return os << "SERVER_UNREACHABLE";
+    case FailState::SERVER_CONTENT_LENGTH_MISMATCH:
+      return os << "SERVER_CONTENT_LENGTH_MISMATCH";
+    case FailState::SERVER_CROSS_ORIGIN_REDIRECT:
+      return os << "SERVER_CROSS_ORIGIN_REDIRECT";
+    case FailState::USER_CANCELED:
+      return os << "USER_CANCELED";
+    case FailState::USER_SHUTDOWN:
+      return os << "USER_SHUTDOWN";
+    case FailState::CRASH:
+      return os << "CRASH";
   }
   CHECK(false) << "state=" << static_cast<int>(state);
   return os;
diff --git a/components/offline_pages/core/background/save_page_request.cc b/components/offline_pages/core/background/save_page_request.cc
index 42fff92..56b391ab 100644
--- a/components/offline_pages/core/background/save_page_request.cc
+++ b/components/offline_pages/core/background/save_page_request.cc
@@ -65,14 +65,43 @@
 
 void SavePageRequest::UpdateFailState(FailState fail_state) {
   // The order of precedence for failure errors related to offline page
-  // downloads is as follows: NO_FAILURE, CANNOT_DOWNLOAD and
-  // NETWORK_INSTABILITY.
+  // downloads is as follows: NO_FAILURE, Failures that are not recoverable and
+  // recoverable failures.
   switch (fail_state) {
     case FailState::NO_FAILURE:  // Intentional fallthrough.
     case FailState::CANNOT_DOWNLOAD:
+    case FailState::FILE_ACCESS_DENIED:
+    case FailState::FILE_NO_SPACE:
+    case FailState::FILE_NAME_TOO_LONG:
+    case FailState::FILE_TOO_LARGE:
+    case FailState::FILE_VIRUS_INFECTED:
+    case FailState::FILE_BLOCKED:
+    case FailState::FILE_SECURITY_CHECK_FAILED:
+    case FailState::FILE_TOO_SHORT:
+    case FailState::FILE_SAME_AS_SOURCE:
+    case FailState::NETWORK_INVALID_REQUEST:
+    case FailState::NETWORK_SERVER_DOWN:
+    case FailState::SERVER_FAILED:
+    case FailState::SERVER_BAD_CONTENT:
+    case FailState::USER_CANCELED:
+    case FailState::USER_SHUTDOWN:
+    case FailState::CRASH:
+    case FailState::SERVER_UNAUTHORIZED:
+    case FailState::SERVER_CERT_PROBLEM:
+    case FailState::SERVER_FORBIDDEN:
+    case FailState::SERVER_UNREACHABLE:
+    case FailState::SERVER_CONTENT_LENGTH_MISMATCH:
+    case FailState::SERVER_NO_RANGE:
+    case FailState::SERVER_CROSS_ORIGIN_REDIRECT:
+    case FailState::FILE_FAILED:
+    case FailState::FILE_HASH_MISMATCH:
       fail_state_ = fail_state;
       break;
+    case FailState::FILE_TRANSIENT_ERROR:  // Intentional fallthrough.
     case FailState::NETWORK_INSTABILITY:
+    case FailState::NETWORK_FAILED:
+    case FailState::NETWORK_TIMEOUT:
+    case FailState::NETWORK_DISCONNECTED:
       if (fail_state_ != FailState::CANNOT_DOWNLOAD) {
         fail_state_ = fail_state;
       }
diff --git a/components/password_manager/core/browser/mock_password_store.h b/components/password_manager/core/browser/mock_password_store.h
index f2aca6a..232d38322 100644
--- a/components/password_manager/core/browser/mock_password_store.h
+++ b/components/password_manager/core/browser/mock_password_store.h
@@ -71,6 +71,7 @@
                std::vector<InteractionsStats>(const GURL& origin_domain));
   MOCK_METHOD1(AddSiteStatsImpl, void(const InteractionsStats&));
   MOCK_METHOD1(RemoveSiteStatsImpl, void(const GURL&));
+  MOCK_CONST_METHOD0(IsAbleToSavePasswords, bool());
 // TODO(crbug.com/706392): Fix password reuse detection for Android.
 #if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
   MOCK_METHOD3(CheckReuse,
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index 96e6a6d..c7aaf35 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -685,7 +685,8 @@
 void PasswordManager::ShowManualFallbackForSaving(
     password_manager::PasswordManagerDriver* driver,
     const PasswordForm& password_form) {
-  if (!client_->IsSavingAndFillingEnabledForCurrentPage() ||
+  if (!client_->GetPasswordStore()->IsAbleToSavePasswords() ||
+      !client_->IsSavingAndFillingEnabledForCurrentPage() ||
       ShouldBlockPasswordForSameOriginButDifferentScheme(password_form) ||
       !client_->GetStoreResultFilter()->ShouldSave(password_form))
     return;
@@ -1072,6 +1073,13 @@
 
   DCHECK(provisional_save_manager_->submitted_form());
 
+  bool able_to_save_passwords =
+      client_->GetPasswordStore()->IsAbleToSavePasswords();
+  UMA_HISTOGRAM_BOOLEAN("PasswordManager.AbleToSavePasswordsOnSuccessfulLogin",
+                        able_to_save_passwords);
+  if (!able_to_save_passwords)
+    return;
+
   MaybeSavePasswordHash();
 
   // TODO(https://crbug.com/831123): Implement checking whether to save with
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index b4c6fa1..4b831093 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -198,6 +198,8 @@
         .WillRepeatedly(Return(password_autofill_manager_.get()));
     EXPECT_CALL(client_, GetMainFrameCertStatus()).WillRepeatedly(Return(0));
 
+    EXPECT_CALL(*store_, IsAbleToSavePasswords()).WillRepeatedly(Return(true));
+
     ON_CALL(client_, GetMainFrameURL()).WillByDefault(ReturnRef(test_url_));
   }
 
@@ -732,6 +734,31 @@
   form_manager_to_save->Save();
 }
 
+TEST_F(PasswordManagerTest, FormSubmitWhenPasswordsCannotBeSaved) {
+  // Test that a plain form submit doesn't result in offering to save passwords.
+  EXPECT_CALL(*store_, IsAbleToSavePasswords()).WillOnce(Return(false));
+
+  PasswordForm form(MakeSimpleForm());
+  std::vector<PasswordForm> observed = {form};
+  EXPECT_CALL(*store_, GetLogins(_, _))
+      .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+  EXPECT_FALSE(manager()->IsPasswordFieldDetectedOnPage());
+  manager()->OnPasswordFormsParsed(&driver_, observed);
+  EXPECT_TRUE(manager()->IsPasswordFieldDetectedOnPage());
+  manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+  EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
+      .WillRepeatedly(Return(true));
+  OnPasswordFormSubmitted(form);
+
+  std::unique_ptr<PasswordFormManagerForUI> form_manager_to_save;
+  EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
+
+  observed.clear();
+  manager()->OnPasswordFormsParsed(&driver_, observed);
+  manager()->OnPasswordFormsRendered(&driver_, observed, true);
+}
+
 // This test verifies a fix for http://crbug.com/236673
 TEST_F(PasswordManagerTest, FormSubmitWithFormOnPreviousPage) {
   PasswordForm first_form(MakeSimpleForm());
@@ -1885,6 +1912,7 @@
     manager()->OnPresaveGeneratedPassword(form);
     ::testing::Mock::VerifyAndClearExpectations(store_.get());
 
+    EXPECT_CALL(*store_, IsAbleToSavePasswords()).WillRepeatedly(Return(true));
     if (!found_matched_logins_in_store)
       EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, presaved_form));
     OnPasswordFormSubmitted(form);
@@ -1894,6 +1922,7 @@
     manager()->OnPasswordFormsRendered(&driver_, observed, true);
 
     ::testing::Mock::VerifyAndClearExpectations(store_.get());
+    EXPECT_CALL(*store_, IsAbleToSavePasswords()).WillRepeatedly(Return(true));
     if (found_matched_logins_in_store) {
       // Credentials should be updated only when the user explicitly chooses.
       ASSERT_TRUE(form_manager);
diff --git a/components/password_manager/core/browser/password_store.cc b/components/password_manager/core/browser/password_store.cc
index 2030ea6f..afdd3ea 100644
--- a/components/password_manager/core/browser/password_store.cc
+++ b/components/password_manager/core/browser/password_store.cc
@@ -619,7 +619,8 @@
 void PasswordStore::OnInitCompleted(bool success) {
   DCHECK(main_task_runner_->RunsTasksInCurrentSequence());
   init_status_ = success ? InitStatus::kSuccess : InitStatus::kFailure;
-  // TODO(tsabolcec): Add UMA histogram to record the success rate.
+
+  UMA_HISTOGRAM_BOOLEAN("PasswordManager.PasswordStoreInitResult", success);
 }
 
 void PasswordStore::Schedule(
diff --git a/components/password_manager/core/browser/password_store.h b/components/password_manager/core/browser/password_store.h
index 8fbbbb5d..796f4d8 100644
--- a/components/password_manager/core/browser/password_store.h
+++ b/components/password_manager/core/browser/password_store.h
@@ -252,7 +252,7 @@
   bool ScheduleTask(base::OnceClosure task);
 
   // Returns true iff initialization was successful.
-  bool IsAbleToSavePasswords() const;
+  virtual bool IsAbleToSavePasswords() const;
 
   base::WeakPtr<syncer::SyncableService> GetPasswordSyncableService();
 
diff --git a/components/policy/core/common/cloud/cloud_policy_core.cc b/components/policy/core/common/cloud/cloud_policy_core.cc
index 471a655..8c5c9fca 100644
--- a/components/policy/core/common/cloud/cloud_policy_core.cc
+++ b/components/policy/core/common/cloud/cloud_policy_core.cc
@@ -29,11 +29,13 @@
     const std::string& policy_type,
     const std::string& settings_entity_id,
     CloudPolicyStore* store,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    network::NetworkConnectionTrackerGetter network_connection_tracker_getter)
     : policy_type_(policy_type),
       settings_entity_id_(settings_entity_id),
       store_(store),
-      task_runner_(task_runner) {}
+      task_runner_(task_runner),
+      network_connection_tracker_getter_(network_connection_tracker_getter) {}
 
 CloudPolicyCore::~CloudPolicyCore() {}
 
@@ -81,7 +83,8 @@
 void CloudPolicyCore::StartRefreshScheduler() {
   if (!refresh_scheduler_) {
     refresh_scheduler_.reset(
-        new CloudPolicyRefreshScheduler(client_.get(), store_, task_runner_));
+        new CloudPolicyRefreshScheduler(client_.get(), store_, task_runner_,
+                                        network_connection_tracker_getter_));
     UpdateRefreshDelayFromPref();
     for (auto& observer : observers_)
       observer.OnRefreshSchedulerStarted(this);
diff --git a/components/policy/core/common/cloud/cloud_policy_core.h b/components/policy/core/common/cloud/cloud_policy_core.h
index ba0279c..5511d63 100644
--- a/components/policy/core/common/cloud/cloud_policy_core.h
+++ b/components/policy/core/common/cloud/cloud_policy_core.h
@@ -13,6 +13,7 @@
 #include "base/observer_list.h"
 #include "components/policy/policy_export.h"
 #include "components/prefs/pref_member.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
 
 class PrefService;
 
@@ -60,7 +61,9 @@
   CloudPolicyCore(const std::string& policy_type,
                   const std::string& settings_entity_id,
                   CloudPolicyStore* store,
-                  const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+                  const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+                  network::NetworkConnectionTrackerGetter
+                      network_connection_tracker_getter);
   ~CloudPolicyCore();
 
   CloudPolicyClient* client() { return client_.get(); }
@@ -124,6 +127,7 @@
   std::string settings_entity_id_;
   CloudPolicyStore* store_;
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  network::NetworkConnectionTrackerGetter network_connection_tracker_getter_;
   std::unique_ptr<CloudPolicyClient> client_;
   std::unique_ptr<CloudPolicyService> service_;
   std::unique_ptr<CloudPolicyRefreshScheduler> refresh_scheduler_;
diff --git a/components/policy/core/common/cloud/cloud_policy_core_unittest.cc b/components/policy/core/common/cloud/cloud_policy_core_unittest.cc
index 4694051..bbcc2d6 100644
--- a/components/policy/core/common/cloud/cloud_policy_core_unittest.cc
+++ b/components/policy/core/common/cloud/cloud_policy_core_unittest.cc
@@ -13,6 +13,7 @@
 #include "components/policy/core/common/policy_pref_names.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace policy {
@@ -24,7 +25,8 @@
       : core_(dm_protocol::kChromeUserPolicyType,
               std::string(),
               &store_,
-              loop_.task_runner()),
+              loop_.task_runner(),
+              network::TestNetworkConnectionTracker::CreateGetter()),
         core_connected_callback_count_(0),
         refresh_scheduler_started_callback_count_(0),
         core_disconnecting_callback_count_(0),
diff --git a/components/policy/core/common/cloud/cloud_policy_manager.cc b/components/policy/core/common/cloud/cloud_policy_manager.cc
index a853c937..02ff985 100644
--- a/components/policy/core/common/cloud/cloud_policy_manager.cc
+++ b/components/policy/core/common/cloud/cloud_policy_manager.cc
@@ -31,8 +31,13 @@
     const std::string& policy_type,
     const std::string& settings_entity_id,
     CloudPolicyStore* cloud_policy_store,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
-    : core_(policy_type, settings_entity_id, cloud_policy_store, task_runner),
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    network::NetworkConnectionTrackerGetter network_connection_tracker_getter)
+    : core_(policy_type,
+            settings_entity_id,
+            cloud_policy_store,
+            task_runner,
+            network_connection_tracker_getter),
       waiting_for_policy_refresh_(false) {}
 
 CloudPolicyManager::~CloudPolicyManager() {}
diff --git a/components/policy/core/common/cloud/cloud_policy_manager.h b/components/policy/core/common/cloud/cloud_policy_manager.h
index 3acdd22..c1bfa5be 100644
--- a/components/policy/core/common/cloud/cloud_policy_manager.h
+++ b/components/policy/core/common/cloud/cloud_policy_manager.h
@@ -17,6 +17,7 @@
 #include "components/policy/core/common/configuration_policy_provider.h"
 #include "components/policy/policy_export.h"
 #include "components/prefs/pref_member.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
 
 namespace base {
 class FilePath;
@@ -44,7 +45,9 @@
       const std::string& policy_type,
       const std::string& settings_entity_id,
       CloudPolicyStore* cloud_policy_store,
-      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+      network::NetworkConnectionTrackerGetter
+          network_connection_tracker_getter);
   ~CloudPolicyManager() override;
 
   CloudPolicyCore* core() { return &core_; }
diff --git a/components/policy/core/common/cloud/cloud_policy_manager_unittest.cc b/components/policy/core/common/cloud/cloud_policy_manager_unittest.cc
index 3ff7a3f6..2fc70659 100644
--- a/components/policy/core/common/cloud/cloud_policy_manager_unittest.cc
+++ b/components/policy/core/common/cloud/cloud_policy_manager_unittest.cc
@@ -20,6 +20,7 @@
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/policy/core/common/schema_registry.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -79,7 +80,8 @@
   // Create and initialize the store.
   store_.NotifyStoreLoaded();
   ConfigurationPolicyProvider* provider = new CloudPolicyManager(
-      dm_protocol::kChromeUserPolicyType, std::string(), &store_, task_runner);
+      dm_protocol::kChromeUserPolicyType, std::string(), &store_, task_runner,
+      network::TestNetworkConnectionTracker::CreateGetter());
   Mock::VerifyAndClearExpectations(&store_);
   return provider;
 }
@@ -144,10 +146,12 @@
   TestCloudPolicyManager(
       CloudPolicyStore* store,
       const scoped_refptr<base::SequencedTaskRunner>& task_runner)
-      : CloudPolicyManager(dm_protocol::kChromeUserPolicyType,
-                           std::string(),
-                           store,
-                           task_runner) {}
+      : CloudPolicyManager(
+            dm_protocol::kChromeUserPolicyType,
+            std::string(),
+            store,
+            task_runner,
+            network::TestNetworkConnectionTracker::CreateGetter()) {}
   ~TestCloudPolicyManager() override {}
 
   // Publish the protected members for testing.
diff --git a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc
index 5838935..49b3361 100644
--- a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc
+++ b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.cc
@@ -57,17 +57,20 @@
 CloudPolicyRefreshScheduler::CloudPolicyRefreshScheduler(
     CloudPolicyClient* client,
     CloudPolicyStore* store,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    network::NetworkConnectionTrackerGetter network_connection_tracker_getter)
     : client_(client),
       store_(store),
       task_runner_(task_runner),
+      network_connection_tracker_(network_connection_tracker_getter.Run()),
       error_retry_delay_ms_(kInitialErrorRetryDelayMs),
       refresh_delay_ms_(kDefaultRefreshDelayMs),
       invalidations_available_(false),
-      creation_time_(base::Time::NowFromSystemTime()) {
+      creation_time_(base::Time::NowFromSystemTime()),
+      weak_factory_(this) {
   client_->AddObserver(this);
   store_->AddObserver(this);
-  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+  network_connection_tracker_->AddNetworkConnectionObserver(this);
 
   UpdateLastRefreshFromPolicy();
   ScheduleRefresh();
@@ -76,7 +79,8 @@
 CloudPolicyRefreshScheduler::~CloudPolicyRefreshScheduler() {
   store_->RemoveObserver(this);
   client_->RemoveObserver(this);
-  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+  if (network_connection_tracker_)
+    network_connection_tracker_->RemoveNetworkConnectionObserver(this);
 }
 
 void CloudPolicyRefreshScheduler::SetDesiredRefreshDelay(
@@ -177,9 +181,9 @@
   // error is required. NB: Changes to is_managed fire OnStoreLoaded().
 }
 
-void CloudPolicyRefreshScheduler::OnNetworkChanged(
-    net::NetworkChangeNotifier::ConnectionType type) {
-  if (type == net::NetworkChangeNotifier::CONNECTION_NONE)
+void CloudPolicyRefreshScheduler::OnConnectionChanged(
+    network::mojom::ConnectionType type) {
+  if (type == network::mojom::ConnectionType::CONNECTION_NONE)
     return;
 
   if (client_->status() == DM_STATUS_REQUEST_FAILED) {
diff --git a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h
index 91b208e..3c8afda 100644
--- a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h
+++ b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h
@@ -14,7 +14,7 @@
 #include "components/policy/core/common/cloud/cloud_policy_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_store.h"
 #include "components/policy/policy_export.h"
-#include "net/base/network_change_notifier.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
 
 namespace base {
 class SequencedTaskRunner;
@@ -27,7 +27,7 @@
 class POLICY_EXPORT CloudPolicyRefreshScheduler
     : public CloudPolicyClient::Observer,
       public CloudPolicyStore::Observer,
-      public net::NetworkChangeNotifier::NetworkChangeObserver {
+      public network::NetworkConnectionTracker::NetworkConnectionObserver {
  public:
   // Refresh constants.
   static const int64_t kDefaultRefreshDelayMs;
@@ -44,7 +44,9 @@
   CloudPolicyRefreshScheduler(
       CloudPolicyClient* client,
       CloudPolicyStore* store,
-      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+      network::NetworkConnectionTrackerGetter
+          network_connection_tracker_getter);
   ~CloudPolicyRefreshScheduler() override;
 
   base::Time last_refresh() const { return last_refresh_; }
@@ -82,10 +84,9 @@
   void OnStoreLoaded(CloudPolicyStore* store) override;
   void OnStoreError(CloudPolicyStore* store) override;
 
-  // net::NetworkChangeNotifier::NetworkChangeObserver:
+  // network::NetworkConnectionTracker::NetworkConnectionObserver:
   // Triggered also when the device wakes up.
-  void OnNetworkChanged(
-      net::NetworkChangeNotifier::ConnectionType type) override;
+  void OnConnectionChanged(network::mojom::ConnectionType type) override;
 
   void set_last_refresh_for_testing(base::Time last_refresh);
 
@@ -120,6 +121,9 @@
   // For scheduling delayed tasks.
   const scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
+  // For listening for network connection changes.
+  network::NetworkConnectionTracker* network_connection_tracker_;
+
   // The delayed refresh callback.
   base::CancelableClosure refresh_callback_;
 
@@ -149,6 +153,8 @@
   // its initial status.
   base::Time creation_time_;
 
+  base::WeakPtrFactory<CloudPolicyRefreshScheduler> weak_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(CloudPolicyRefreshScheduler);
 };
 
diff --git a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler_unittest.cc b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler_unittest.cc
index c9f9b2d..3959872 100644
--- a/components/policy/core/common/cloud/cloud_policy_refresh_scheduler_unittest.cc
+++ b/components/policy/core/common/cloud/cloud_policy_refresh_scheduler_unittest.cc
@@ -18,6 +18,7 @@
 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_client.h"
 #include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -38,8 +39,7 @@
 class CloudPolicyRefreshSchedulerTest : public testing::Test {
  protected:
   CloudPolicyRefreshSchedulerTest()
-      : task_runner_(new base::TestSimpleTaskRunner()),
-        network_change_notifier_(net::NetworkChangeNotifier::CreateMock()) {}
+      : task_runner_(new base::TestSimpleTaskRunner()) {}
 
   void SetUp() override {
     client_.SetDMToken("token");
@@ -59,15 +59,18 @@
 
   CloudPolicyRefreshScheduler* CreateRefreshScheduler() {
     EXPECT_EQ(0u, task_runner_->NumPendingTasks());
-    CloudPolicyRefreshScheduler* scheduler =
-        new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_);
+    CloudPolicyRefreshScheduler* scheduler = new CloudPolicyRefreshScheduler(
+        &client_, &store_, task_runner_,
+        network::TestNetworkConnectionTracker::CreateGetter());
+    // Make sure the NetworkConnectionTracker has been set up.
+    base::RunLoop().RunUntilIdle();
     scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate);
     return scheduler;
   }
 
-  void NotifyNetworkChanged() {
-    net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
-        net::NetworkChangeNotifier::CONNECTION_WIFI);
+  void NotifyConnectionChanged() {
+    network::TestNetworkConnectionTracker::GetInstance()->SetConnectionType(
+        network::mojom::ConnectionType::CONNECTION_WIFI);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -166,7 +169,6 @@
   MockCloudPolicyClient client_;
   MockCloudPolicyStore store_;
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
 
   // Base time for the refresh that the scheduler should be using.
   base::Time last_update_;
@@ -266,7 +268,9 @@
 
 TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsAvailable) {
   std::unique_ptr<CloudPolicyRefreshScheduler> scheduler(
-      new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_));
+      new CloudPolicyRefreshScheduler(
+          &client_, &store_, task_runner_,
+          network::TestNetworkConnectionTracker::CreateGetter()));
   scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate);
 
   // The scheduler has scheduled refreshes at the initial refresh rate.
@@ -295,7 +299,9 @@
 
 TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsNotAvailable) {
   std::unique_ptr<CloudPolicyRefreshScheduler> scheduler(
-      new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_));
+      new CloudPolicyRefreshScheduler(
+          &client_, &store_, task_runner_,
+          network::TestNetworkConnectionTracker::CreateGetter()));
   scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate);
 
   // Signal that invalidations are not available. The scheduler will not
@@ -325,7 +331,9 @@
 
 TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsOffAndOn) {
   std::unique_ptr<CloudPolicyRefreshScheduler> scheduler(
-      new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_));
+      new CloudPolicyRefreshScheduler(
+          &client_, &store_, task_runner_,
+          network::TestNetworkConnectionTracker::CreateGetter()));
   scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate);
   scheduler->SetInvalidationServiceAvailability(true);
   // Initial fetch.
@@ -352,7 +360,9 @@
 
 TEST_F(CloudPolicyRefreshSchedulerTest, InvalidationsDisconnected) {
   std::unique_ptr<CloudPolicyRefreshScheduler> scheduler(
-      new CloudPolicyRefreshScheduler(&client_, &store_, task_runner_));
+      new CloudPolicyRefreshScheduler(
+          &client_, &store_, task_runner_,
+          network::TestNetworkConnectionTracker::CreateGetter()));
   scheduler->SetDesiredRefreshDelay(kPolicyRefreshRate);
   scheduler->SetInvalidationServiceAvailability(true);
   // Initial fetch.
@@ -375,7 +385,7 @@
   CheckTiming(kPolicyRefreshRate);
 }
 
-TEST_F(CloudPolicyRefreshSchedulerTest, OnNetworkChangedUnregistered) {
+TEST_F(CloudPolicyRefreshSchedulerTest, OnConnectionChangedUnregistered) {
   client_.SetDMToken(std::string());
   std::unique_ptr<CloudPolicyRefreshScheduler> scheduler(
       CreateRefreshScheduler());
@@ -384,14 +394,16 @@
   EXPECT_FALSE(task_runner_->HasPendingTask());
 
   EmulateSleepThroughLastRefreshTime(scheduler.get());
-  scheduler->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_WIFI);
+  scheduler->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_WIFI);
   EXPECT_FALSE(task_runner_->HasPendingTask());
 }
+
 // TODO(igorcov): Before sleep in normal flow there's a task pending. When the
-// device wakes up, OnNetworkChanged is called which should cancel the
+// device wakes up, OnConnectionChanged is called which should cancel the
 // pending task and queue a new task to run earlier. It is desirable to
 // simulate that flow here.
-TEST_F(CloudPolicyRefreshSchedulerTest, OnNetworkChangedAfterSleep) {
+TEST_F(CloudPolicyRefreshSchedulerTest, OnConnectionChangedAfterSleep) {
   std::unique_ptr<CloudPolicyRefreshScheduler> scheduler(
       CreateRefreshScheduler());
 
@@ -401,7 +413,8 @@
   EXPECT_FALSE(task_runner_->HasPendingTask());
 
   EmulateSleepThroughLastRefreshTime(scheduler.get());
-  scheduler->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_WIFI);
+  scheduler->OnConnectionChanged(
+      network::mojom::ConnectionType::CONNECTION_WIFI);
   EXPECT_TRUE(task_runner_->HasPendingTask());
   task_runner_->ClearPendingTasks();
 }
@@ -464,9 +477,9 @@
   CheckTiming(CloudPolicyRefreshScheduler::kRefreshDelayMaxMs);
 }
 
-TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnNetworkChanged) {
+TEST_F(CloudPolicyRefreshSchedulerSteadyStateTest, OnConnectionChanged) {
   client_.SetStatus(DM_STATUS_REQUEST_FAILED);
-  NotifyNetworkChanged();
+  NotifyConnectionChanged();
   EXPECT_EQ(GetLastDelay(), base::TimeDelta());
 }
 
diff --git a/components/policy/core/common/cloud/component_cloud_policy_service_unittest.cc b/components/policy/core/common/cloud/component_cloud_policy_service_unittest.cc
index 1f2643e..d3cdd08a 100644
--- a/components/policy/core/common/cloud/component_cloud_policy_service_unittest.cc
+++ b/components/policy/core/common/cloud/component_cloud_policy_service_unittest.cc
@@ -32,6 +32,7 @@
 #include "crypto/rsa_private_key.h"
 #include "crypto/sha2.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -98,7 +99,8 @@
         core_(dm_protocol::kChromeUserPolicyType,
               std::string(),
               &store_,
-              loop_.task_runner()) {
+              loop_.task_runner(),
+              network::TestNetworkConnectionTracker::CreateGetter()) {
     builder_.SetDefaultSigningKey();
     builder_.policy_data().set_policy_type(
         dm_protocol::kChromeExtensionPolicyType);
diff --git a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.cc b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.cc
index 604609ee..38e9e29 100644
--- a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.cc
+++ b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.cc
@@ -27,11 +27,13 @@
     std::unique_ptr<MachineLevelUserCloudPolicyStore> store,
     std::unique_ptr<CloudExternalDataManager> external_data_manager,
     const base::FilePath& policy_dir,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    network::NetworkConnectionTrackerGetter network_connection_tracker_getter)
     : CloudPolicyManager(dm_protocol::kChromeMachineLevelUserCloudPolicyType,
                          std::string(),
                          store.get(),
-                         task_runner),
+                         task_runner,
+                         network_connection_tracker_getter),
       store_(std::move(store)),
       external_data_manager_(std::move(external_data_manager)),
       policy_dir_(policy_dir) {}
diff --git a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h
index f9586a1..956c9fbc 100644
--- a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h
+++ b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "components/policy/core/common/cloud/cloud_policy_manager.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
 
 class PrefService;
 
@@ -25,7 +26,9 @@
       std::unique_ptr<MachineLevelUserCloudPolicyStore> store,
       std::unique_ptr<CloudExternalDataManager> external_data_manager,
       const base::FilePath& policy_dir,
-      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+      network::NetworkConnectionTrackerGetter
+          network_connection_tracker_getter);
   ~MachineLevelUserCloudPolicyManager() override;
 
   // Initializes the cloud connection. |local_state| must stay valid until this
diff --git a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager_unittest.cc b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager_unittest.cc
index 95dc481a..bc7ceb4 100644
--- a/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager_unittest.cc
+++ b/components/policy/core/common/cloud/machine_level_user_cloud_policy_manager_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/sequenced_task_runner.h"
 #include "components/policy/core/common/cloud/cloud_external_data_manager.h"
 #include "components/policy/core/common/cloud/machine_level_user_cloud_policy_store.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -40,7 +41,8 @@
     store_ = store.get();
     manager_ = std::make_unique<MachineLevelUserCloudPolicyManager>(
         std::move(store), std::unique_ptr<CloudExternalDataManager>(),
-        base::FilePath(), scoped_refptr<base::SequencedTaskRunner>());
+        base::FilePath(), scoped_refptr<base::SequencedTaskRunner>(),
+        network::TestNetworkConnectionTracker::CreateGetter());
   }
 
   SchemaRegistry schema_registry_;
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.cc b/components/policy/core/common/cloud/user_cloud_policy_manager.cc
index 0f8e1ad..ea512ca 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_manager.cc
+++ b/components/policy/core/common/cloud/user_cloud_policy_manager.cc
@@ -30,11 +30,13 @@
     std::unique_ptr<UserCloudPolicyStore> store,
     const base::FilePath& component_policy_cache_path,
     std::unique_ptr<CloudExternalDataManager> external_data_manager,
-    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+    network::NetworkConnectionTrackerGetter network_connection_tracker_getter)
     : CloudPolicyManager(dm_protocol::kChromeUserPolicyType,
                          std::string(),
                          store.get(),
-                         task_runner),
+                         task_runner,
+                         network_connection_tracker_getter),
       store_(std::move(store)),
       component_policy_cache_path_(component_policy_cache_path),
       external_data_manager_(std::move(external_data_manager)) {}
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager.h b/components/policy/core/common/cloud/user_cloud_policy_manager.h
index 5125a5ce..f781e24 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_manager.h
+++ b/components/policy/core/common/cloud/user_cloud_policy_manager.h
@@ -14,6 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "components/policy/core/common/cloud/cloud_policy_manager.h"
 #include "components/policy/policy_export.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
 
 class AccountId;
 class PrefService;
@@ -40,7 +41,9 @@
       std::unique_ptr<UserCloudPolicyStore> store,
       const base::FilePath& component_policy_cache_path,
       std::unique_ptr<CloudExternalDataManager> external_data_manager,
-      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner,
+      network::NetworkConnectionTrackerGetter
+          network_connection_tracker_getter);
   ~UserCloudPolicyManager() override;
 
   // ConfigurationPolicyProvider overrides:
diff --git a/components/policy/core/common/cloud/user_cloud_policy_manager_unittest.cc b/components/policy/core/common/cloud/user_cloud_policy_manager_unittest.cc
index 01ac79c..656054fe 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_manager_unittest.cc
+++ b/components/policy/core/common/cloud/user_cloud_policy_manager_unittest.cc
@@ -14,6 +14,7 @@
 #include "components/policy/core/common/mock_configuration_policy_provider.h"
 #include "components/policy/core/common/policy_types.h"
 #include "components/policy/core/common/schema_registry.h"
+#include "services/network/test/test_network_connection_tracker.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -53,7 +54,8 @@
     const auto task_runner = scoped_task_environment_.GetMainThreadTaskRunner();
     manager_.reset(new UserCloudPolicyManager(
         std::unique_ptr<UserCloudPolicyStore>(store_), base::FilePath(),
-        std::unique_ptr<CloudExternalDataManager>(), task_runner));
+        std::unique_ptr<CloudExternalDataManager>(), task_runner,
+        network::TestNetworkConnectionTracker::CreateGetter()));
     manager_->Init(&schema_registry_);
     manager_->AddObserver(&observer_);
     Mock::VerifyAndClearExpectations(store_);
diff --git a/components/safe_browsing/db/v4_store.cc b/components/safe_browsing/db/v4_store.cc
index c1c6d496..e1cba619 100644
--- a/components/safe_browsing/db/v4_store.cc
+++ b/components/safe_browsing/db/v4_store.cc
@@ -486,14 +486,9 @@
 
   for (const auto& iterator_pair : iterator_map) {
     PrefixSize prefix_size = iterator_pair.first;
-    CHECK_GE(prefix_size, 4u);  // Convert to DCHECK after fixing 787460.
     HashPrefixes::const_iterator start = iterator_pair.second;
 
-    CHECK(hash_prefix_map.end() !=
-          hash_prefix_map.find(
-              prefix_size));  // Convert to DCHECK after fixing 787460.
     const HashPrefixes& hash_prefixes = hash_prefix_map.at(prefix_size);
-
     PrefixSize distance = std::distance(start, hash_prefixes.end());
     CHECK_EQ(0u, distance % prefix_size);
     if (prefix_size <= distance) {
@@ -595,14 +590,12 @@
 
       // Update the iterator map, which means that we have merged one hash
       // prefix of size |next_smallest_prefix_size| from the old store.
-      old_iterator_map.at(next_smallest_prefix_size) +=
-          next_smallest_prefix_size;
+      old_iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size;
 
       if (!raw_removals || removals_iter == raw_removals->end() ||
           *removals_iter != total_picked_from_old) {
         // Append the smallest hash to the appropriate list.
-        hash_prefix_map_.at(next_smallest_prefix_size) +=
-            next_smallest_prefix_old;
+        hash_prefix_map_[next_smallest_prefix_size] += next_smallest_prefix_old;
 
         if (calculate_checksum) {
           checksum_ctx->Update(next_smallest_prefix_old.data(),
@@ -622,7 +615,7 @@
       next_smallest_prefix_size = next_smallest_prefix_additions.size();
 
       // Append the smallest hash to the appropriate list.
-      hash_prefix_map_.at(next_smallest_prefix_size) +=
+      hash_prefix_map_[next_smallest_prefix_size] +=
           next_smallest_prefix_additions;
 
       if (calculate_checksum) {
@@ -632,7 +625,7 @@
 
       // Update the iterator map, which means that we have merged one hash
       // prefix of size |next_smallest_prefix_size| from the update.
-      additions_iterator_map.at(next_smallest_prefix_size) +=
+      additions_iterator_map[next_smallest_prefix_size] +=
           next_smallest_prefix_size;
 
       // Find the next smallest unmerged element in the additions map.
@@ -811,12 +804,11 @@
   std::unique_ptr<crypto::SecureHash> checksum_ctx(
       crypto::SecureHash::Create(crypto::SecureHash::SHA256));
   while (has_unmerged) {
-    PrefixSize next_smallest_prefix_size;
-    next_smallest_prefix_size = next_smallest_prefix.size();
+    PrefixSize next_smallest_prefix_size = next_smallest_prefix.size();
 
     // Update the iterator map, which means that we have read one hash
     // prefix of size |next_smallest_prefix_size| from hash_prefix_map_.
-    iterator_map.at(next_smallest_prefix_size) += next_smallest_prefix_size;
+    iterator_map[next_smallest_prefix_size] += next_smallest_prefix_size;
 
     checksum_ctx->Update(next_smallest_prefix.data(),
                          next_smallest_prefix_size);
diff --git a/components/safe_browsing/features.cc b/components/safe_browsing/features.cc
index fd6063a..8f3c7ce 100644
--- a/components/safe_browsing/features.cc
+++ b/components/safe_browsing/features.cc
@@ -55,6 +55,9 @@
     "SafeBrowsingTriggerThrottlerDailyQuota",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kUseLocalBlacklistsV2{"SafeBrowsingUseLocalBlacklistsV2",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
 namespace {
 // List of experimental features. Boolean value for each list member should be
 // set to true if the experiment is currently running at a probability other
@@ -73,6 +76,7 @@
     {&kSuspiciousSiteTriggerQuotaFeature, true},
     {&kThreatDomDetailsTagAndAttributeFeature, false},
     {&kTriggerThrottlerDailyQuotaFeature, false},
+    {&kUseLocalBlacklistsV2, true},
 };
 
 // Adds the name and the enabled/disabled status of a given feature.
diff --git a/components/safe_browsing/features.h b/components/safe_browsing/features.h
index 5d7dead..4b552c8a 100644
--- a/components/safe_browsing/features.h
+++ b/components/safe_browsing/features.h
@@ -58,6 +58,9 @@
 // trials simultaneously.
 extern const base::Feature kTriggerThrottlerDailyQuotaFeature;
 
+// Controls whether Chrome on Android uses locally cached blacklists.
+extern const base::Feature kUseLocalBlacklistsV2;
+
 base::ListValue GetFeatureStatusList();
 
 }  // namespace safe_browsing
diff --git a/components/viz/common/resources/resource_format_utils.cc b/components/viz/common/resources/resource_format_utils.cc
index b8b89bcc..57c8212d 100644
--- a/components/viz/common/resources/resource_format_utils.cc
+++ b/components/viz/common/resources/resource_format_utils.cc
@@ -211,8 +211,6 @@
       return gfx::BufferFormat::RGBA_4444;
     case RGBA_8888:
       return gfx::BufferFormat::RGBA_8888;
-    case ETC1:
-      return gfx::BufferFormat::ETC1;
     case RGBA_F16:
       return gfx::BufferFormat::RGBA_F16;
     case BGR_565:
@@ -233,6 +231,7 @@
       return gfx::BufferFormat::YUV_420_BIPLANAR;
     case UYVY_422:
       return gfx::BufferFormat::UYVY_422;
+    case ETC1:
     case ALPHA_8:
     case LUMINANCE_8:
     case RGB_565:
@@ -296,11 +295,11 @@
     case R16_EXT:
     case RGBA_4444:
     case RGBA_8888:
-    case ETC1:
     case RGBA_F16:
       return true;
     // These formats have no BufferFormat equivalent or are only used
     // for external textures, or have no GL equivalent formats.
+    case ETC1:
     case ALPHA_8:
     case LUMINANCE_8:
     case RGB_565:
@@ -361,8 +360,6 @@
       return RGBA_4444;
     case gfx::BufferFormat::RGBA_8888:
       return RGBA_8888;
-    case gfx::BufferFormat::ETC1:
-      return ETC1;
     case gfx::BufferFormat::RGBA_F16:
       return RGBA_F16;
     case gfx::BufferFormat::BGR_565:
diff --git a/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc b/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
index 07c8df0..e534bb0 100644
--- a/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
+++ b/components/viz/host/host_gpu_memory_buffer_manager_unittest.cc
@@ -294,7 +294,6 @@
   const auto buffer_id = static_cast<gfx::GpuMemoryBufferId>(1);
   const int client_id = 2;
   // SCANOUT cannot be used if native gpu memory buffer is not supported.
-  // When ATC is used, both width and height should be multiples of 4.
   struct {
     gfx::BufferUsage usage;
     gfx::BufferFormat format;
@@ -302,7 +301,6 @@
     bool expect_null_handle;
   } configs[] = {
       {gfx::BufferUsage::SCANOUT, gfx::BufferFormat::YVU_420, {10, 20}, true},
-      {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::ATC, {10, 20}, true},
       {gfx::BufferUsage::GPU_READ, gfx::BufferFormat::YVU_420, {64, 64}, false},
   };
   for (const auto& config : configs) {
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 2a6d377..3fa0f48d 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -282,6 +282,8 @@
     sources += [
       "display_embedder/gl_output_surface_android.cc",
       "display_embedder/gl_output_surface_android.h",
+      "display_embedder/gl_output_surface_buffer_queue_android.cc",
+      "display_embedder/gl_output_surface_buffer_queue_android.h",
     ]
   }
 
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc
new file mode 100644
index 0000000..7739592
--- /dev/null
+++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.cc
@@ -0,0 +1,46 @@
+// 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/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h"
+
+#include "components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace viz {
+
+GLOutputSurfaceBufferQueueAndroid::GLOutputSurfaceBufferQueueAndroid(
+    scoped_refptr<VizProcessContextProvider> context_provider,
+    gpu::SurfaceHandle surface_handle,
+    SyntheticBeginFrameSource* synthetic_begin_frame_source,
+    gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+    gfx::BufferFormat buffer_format)
+    : GLOutputSurfaceBufferQueue(context_provider,
+                                 surface_handle,
+                                 synthetic_begin_frame_source,
+                                 gpu_memory_buffer_manager,
+                                 GL_TEXTURE_2D,
+                                 GL_RGBA,
+                                 buffer_format),
+      overlay_candidate_validator_(
+          std::make_unique<CompositorOverlayCandidateValidatorAndroid>()) {}
+
+GLOutputSurfaceBufferQueueAndroid::~GLOutputSurfaceBufferQueueAndroid() =
+    default;
+
+void GLOutputSurfaceBufferQueueAndroid::HandlePartialSwap(
+    const gfx::Rect& sub_buffer_rect,
+    uint32_t flags,
+    gpu::ContextSupport::SwapCompletedCallback swap_callback,
+    gpu::ContextSupport::PresentationCallback presentation_callback) {
+  DCHECK(sub_buffer_rect.IsEmpty());
+  context_provider_->ContextSupport()->CommitOverlayPlanes(
+      flags, std::move(swap_callback), std::move(presentation_callback));
+}
+
+OverlayCandidateValidator*
+GLOutputSurfaceBufferQueueAndroid::GetOverlayCandidateValidator() const {
+  return overlay_candidate_validator_.get();
+}
+
+}  // namespace viz
diff --git a/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h
new file mode 100644
index 0000000..822a78d7
--- /dev/null
+++ b/components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_BUFFER_QUEUE_ANDROID_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_BUFFER_QUEUE_ANDROID_H_
+
+#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
+#include "ui/gfx/buffer_types.h"
+
+namespace viz {
+
+class GLOutputSurfaceBufferQueueAndroid : public GLOutputSurfaceBufferQueue {
+ public:
+  GLOutputSurfaceBufferQueueAndroid(
+      scoped_refptr<VizProcessContextProvider> context_provider,
+      gpu::SurfaceHandle surface_handle,
+      SyntheticBeginFrameSource* synthetic_begin_frame_source,
+      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+      gfx::BufferFormat buffer_format);
+  ~GLOutputSurfaceBufferQueueAndroid() override;
+
+  // GLOutputSurfaceBufferQueue implementation:
+  void HandlePartialSwap(
+      const gfx::Rect& sub_buffer_rect,
+      uint32_t flags,
+      gpu::ContextSupport::SwapCompletedCallback swap_callback,
+      gpu::ContextSupport::PresentationCallback presentation_callback) override;
+  OverlayCandidateValidator* GetOverlayCandidateValidator() const override;
+
+ private:
+  std::unique_ptr<OverlayCandidateValidator> overlay_candidate_validator_;
+
+  DISALLOW_COPY_AND_ASSIGN(GLOutputSurfaceBufferQueueAndroid);
+};
+
+}  // namespace viz
+
+#endif  // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_GL_OUTPUT_SURFACE_BUFFER_QUEUE_ANDROID_H_
diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc
index 155ef82..c775cbb 100644
--- a/components/viz/service/display_embedder/gpu_display_provider.cc
+++ b/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -36,6 +36,7 @@
 
 #if defined(OS_ANDROID)
 #include "components/viz/service/display_embedder/gl_output_surface_android.h"
+#include "components/viz/service/display_embedder/gl_output_surface_buffer_queue_android.h"
 #endif
 
 #if defined(OS_MACOSX)
@@ -169,6 +170,13 @@
           std::move(context_provider), surface_handle,
           synthetic_begin_frame_source, gpu_memory_buffer_manager_.get(),
           renderer_settings.allow_overlays);
+#elif defined(OS_ANDROID)
+      // TODO(khushalsagar): Use RGB_565 if specified by context provider.
+      auto buffer_format = gfx::BufferFormat::RGBA_8888;
+      output_surface = std::make_unique<GLOutputSurfaceBufferQueueAndroid>(
+          std::move(context_provider), surface_handle,
+          synthetic_begin_frame_source, gpu_memory_buffer_manager_.get(),
+          buffer_format);
 #else
       NOTREACHED();
 #endif
diff --git a/components/viz/service/display_embedder/viz_process_context_provider.cc b/components/viz/service/display_embedder/viz_process_context_provider.cc
index da36ef4..d5840b3 100644
--- a/components/viz/service/display_embedder/viz_process_context_provider.cc
+++ b/components/viz/service/display_embedder/viz_process_context_provider.cc
@@ -191,6 +191,11 @@
   command_buffer_->SetUpdateVSyncParametersCallback(callback);
 }
 
+bool VizProcessContextProvider::UseRGB565PixelFormat() const {
+  return attributes_.alpha_size == 0 && attributes_.red_size == 5 &&
+         attributes_.green_size == 6 && attributes_.blue_size == 5;
+}
+
 void VizProcessContextProvider::InitializeContext(
     scoped_refptr<gpu::CommandBufferTaskExecutor> task_executor,
     gpu::SurfaceHandle surface_handle,
diff --git a/components/viz/service/display_embedder/viz_process_context_provider.h b/components/viz/service/display_embedder/viz_process_context_provider.h
index 960aa48..81ee002 100644
--- a/components/viz/service/display_embedder/viz_process_context_provider.h
+++ b/components/viz/service/display_embedder/viz_process_context_provider.h
@@ -73,6 +73,7 @@
   void SetUpdateVSyncParametersCallback(
       const gpu::InProcessCommandBuffer::UpdateVSyncParametersCallback&
           callback);
+  bool UseRGB565PixelFormat() const;
 
  private:
   friend class base::RefCountedThreadSafe<VizProcessContextProvider>;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 683a7f3..df70575 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -319,6 +319,8 @@
     "android/content_protocol_handler_impl.h",
     "android/content_startup_flags.cc",
     "android/content_startup_flags.h",
+    "android/content_url_loader_factory.cc",
+    "android/content_url_loader_factory.h",
     "android/devtools_auth.cc",
     "android/dialog_overlay_impl.cc",
     "android/dialog_overlay_impl.h",
diff --git a/content/browser/android/content_url_loader_factory.cc b/content/browser/android/content_url_loader_factory.cc
new file mode 100644
index 0000000..25cc7e7
--- /dev/null
+++ b/content/browser/android/content_url_loader_factory.cc
@@ -0,0 +1,261 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/android/content_url_loader_factory.h"
+
+#include <string>
+#include <vector>
+
+#include "base/android/content_uri_utils.h"
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/file_url_loader.h"
+#include "content/public/common/content_client.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/file_data_pipe_producer.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_byte_range.h"
+#include "net/http/http_util.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+
+// TODO(eroman): Add unit-tests for "X-Chrome-intent-type"
+//               (see url_request_content_job_unittest.cc).
+// TODO(eroman): Remove duplication with file_url_loader_factory.cc (notably
+//               Range header parsing).
+
+namespace content {
+namespace {
+
+constexpr size_t kDefaultContentUrlPipeSize = 65536;
+
+// Assigns the byte range that has been requested based on the Range header.
+// This assumes the simplest form of the Range header using a single range.
+// If no byte range was specified, the output range will cover the entire file.
+bool GetRequestedByteRange(const network::ResourceRequest& request,
+                           size_t content_size,
+                           size_t* first_byte_to_send,
+                           size_t* total_bytes_to_send) {
+  *first_byte_to_send = 0;
+  *total_bytes_to_send = content_size;
+
+  std::string range_header;
+  std::vector<net::HttpByteRange> ranges;
+
+  if (!request.headers.GetHeader(net::HttpRequestHeaders::kRange,
+                                 &range_header) ||
+      !net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
+    return true;
+  }
+
+  // Only handle a simple Range header for a single range.
+  net::HttpByteRange byte_range = ranges[0];
+  if (ranges.size() != 1 || !byte_range.ComputeBounds(content_size))
+    return false;
+
+  *first_byte_to_send = static_cast<size_t>(byte_range.first_byte_position());
+  *total_bytes_to_send = static_cast<size_t>(byte_range.last_byte_position()) -
+                         *first_byte_to_send + 1;
+  return true;
+}
+
+// Gets the mimetype for |content_path| either by asking the content provider,
+// or by using the special Chrome request header X-Chrome-intent-type.
+void GetMimeType(const network::ResourceRequest& request,
+                 const base::FilePath& content_path,
+                 std::string* out_mime_type) {
+  out_mime_type->clear();
+
+  std::string intent_type_header;
+  if ((request.resource_type == content::RESOURCE_TYPE_MAIN_FRAME) &&
+      request.headers.GetHeader("X-Chrome-intent-type", &intent_type_header)) {
+    *out_mime_type = intent_type_header;
+  }
+
+  if (out_mime_type->empty())
+    *out_mime_type = base::GetContentUriMimeType(content_path);
+}
+
+class ContentURLLoader : public network::mojom::URLLoader {
+ public:
+  static void CreateAndStart(
+      const network::ResourceRequest& request,
+      network::mojom::URLLoaderRequest loader,
+      network::mojom::URLLoaderClientPtrInfo client_info) {
+    // Owns itself. Will live as long as its URLLoader and URLLoaderClientPtr
+    // bindings are alive - essentially until either the client gives up or all
+    // file data has been sent to it.
+    auto* content_url_loader = new ContentURLLoader;
+    content_url_loader->Start(request, std::move(loader),
+                              std::move(client_info));
+  }
+
+  // network::mojom::URLLoader:
+  void FollowRedirect(const base::Optional<std::vector<std::string>>&
+                          to_be_removed_request_headers,
+                      const base::Optional<net::HttpRequestHeaders>&
+                          modified_request_headers) override {}
+  void ProceedWithResponse() override {}
+  void SetPriority(net::RequestPriority priority,
+                   int32_t intra_priority_value) override {}
+  void PauseReadingBodyFromNet() override {}
+  void ResumeReadingBodyFromNet() override {}
+
+ private:
+  ContentURLLoader() : binding_(this) {}
+  ~ContentURLLoader() override = default;
+
+  void Start(const network::ResourceRequest& request,
+             network::mojom::URLLoaderRequest loader,
+             network::mojom::URLLoaderClientPtrInfo client_info) {
+    network::ResourceResponseHead head;
+    head.request_start = head.response_start = base::TimeTicks::Now();
+    binding_.Bind(std::move(loader));
+    binding_.set_connection_error_handler(base::BindOnce(
+        &ContentURLLoader::OnConnectionError, base::Unretained(this)));
+
+    network::mojom::URLLoaderClientPtr client;
+    client.Bind(std::move(client_info));
+
+    DCHECK(request.url.SchemeIs("content"));
+    base::FilePath path = base::FilePath(request.url.spec());
+
+    // Get the file length.
+    base::File::Info info;
+    if (!base::GetFileInfo(path, &info))
+      return CompleteWithFailure(std::move(client), net::ERR_FILE_NOT_FOUND);
+
+    size_t first_byte_to_send;
+    size_t total_bytes_to_send;
+    if (!GetRequestedByteRange(request, info.size, &first_byte_to_send,
+                               &total_bytes_to_send)) {
+      return CompleteWithFailure(std::move(client),
+                                 net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
+    }
+
+    mojo::DataPipe pipe(kDefaultContentUrlPipeSize);
+    if (!pipe.consumer_handle.is_valid()) {
+      return CompleteWithFailure(std::move(client), net::ERR_FAILED);
+    }
+
+    base::File file = base::OpenContentUriForRead(path);
+    if (!file.IsValid()) {
+      return CompleteWithFailure(
+          std::move(client), net::FileErrorToNetError(file.error_details()));
+      return;
+    }
+
+    total_bytes_written_ = total_bytes_to_send;
+    head.content_length = base::saturated_cast<int64_t>(total_bytes_to_send);
+
+    // Set the mimetype of the response.
+    GetMimeType(request, path, &head.mime_type);
+    if (!head.mime_type.empty() && head.headers) {
+      head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+      head.headers->AddHeader(
+          base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType,
+                             head.mime_type.c_str()));
+    }
+
+    client->OnReceiveResponse(head);
+    client->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
+    client_ = std::move(client);
+
+    if (total_bytes_to_send == 0) {
+      // There's no more data, so we're already done.
+      OnFileWritten(MOJO_RESULT_OK);
+      return;
+    }
+
+    // In case of a range request, seek to the appropriate position before
+    // sending the remaining bytes asynchronously. Under normal conditions
+    // (i.e., no range request) this Seek is effectively a no-op.
+    file.Seek(base::File::FROM_BEGIN, static_cast<int64_t>(first_byte_to_send));
+
+    data_producer_ = std::make_unique<mojo::FileDataPipeProducer>(
+        std::move(pipe.producer_handle), /*observer=*/nullptr);
+    data_producer_->WriteFromFile(
+        std::move(file), total_bytes_to_send,
+        base::BindOnce(&ContentURLLoader::OnFileWritten,
+                       base::Unretained(this)));
+  }
+
+  void CompleteWithFailure(network::mojom::URLLoaderClientPtr client,
+                           net::Error net_error) {
+    client->OnComplete(network::URLLoaderCompletionStatus(net_error));
+    MaybeDeleteSelf();
+  }
+
+  void OnConnectionError() {
+    binding_.Close();
+    MaybeDeleteSelf();
+  }
+
+  void MaybeDeleteSelf() {
+    if (!binding_.is_bound() && !client_.is_bound())
+      delete this;
+  }
+
+  void OnFileWritten(MojoResult result) {
+    // All the data has been written now. Close the data pipe. The consumer will
+    // be notified that there will be no more data to read from now.
+    data_producer_.reset();
+
+    if (result == MOJO_RESULT_OK) {
+      network::URLLoaderCompletionStatus status(net::OK);
+      status.encoded_data_length = total_bytes_written_;
+      status.encoded_body_length = total_bytes_written_;
+      status.decoded_body_length = total_bytes_written_;
+      client_->OnComplete(status);
+    } else {
+      client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED));
+    }
+    client_.reset();
+    MaybeDeleteSelf();
+  }
+
+  std::unique_ptr<mojo::FileDataPipeProducer> data_producer_;
+  mojo::Binding<network::mojom::URLLoader> binding_;
+  network::mojom::URLLoaderClientPtr client_;
+
+  // In case of successful loads, this holds the total of bytes written.
+  // It is used to set some of the URLLoaderCompletionStatus data passed back
+  // to the URLLoaderClients (eg SimpleURLLoader).
+  size_t total_bytes_written_ = 0;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentURLLoader);
+};
+
+}  // namespace
+
+ContentURLLoaderFactory::ContentURLLoaderFactory(
+    scoped_refptr<base::SequencedTaskRunner> task_runner)
+    : task_runner_(std::move(task_runner)) {}
+
+ContentURLLoaderFactory::~ContentURLLoaderFactory() = default;
+
+void ContentURLLoaderFactory::CreateLoaderAndStart(
+    network::mojom::URLLoaderRequest loader,
+    int32_t routing_id,
+    int32_t request_id,
+    uint32_t options,
+    const network::ResourceRequest& request,
+    network::mojom::URLLoaderClientPtr client,
+    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+  task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(&ContentURLLoader::CreateAndStart, request,
+                                std::move(loader), client.PassInterface()));
+}
+
+void ContentURLLoaderFactory::Clone(
+    network::mojom::URLLoaderFactoryRequest loader) {
+  bindings_.AddBinding(this, std::move(loader));
+}
+
+}  // namespace content
diff --git a/content/browser/android/content_url_loader_factory.h b/content/browser/android/content_url_loader_factory.h
new file mode 100644
index 0000000..8cbe8c6
--- /dev/null
+++ b/content/browser/android/content_url_loader_factory.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_ANDROID_CONTENT_URL_LOADER_FACTORY_H_
+#define CONTENT_BROWSER_ANDROID_CONTENT_URL_LOADER_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/sequenced_task_runner.h"
+#include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace content {
+
+// A URLLoaderFactory used for the content:// scheme used when Network Service
+// is enabled.
+class CONTENT_EXPORT ContentURLLoaderFactory
+    : public network::mojom::URLLoaderFactory {
+ public:
+  // SequencedTaskRunner must be allowed to block and should have background
+  // priority since it will be used to schedule synchronous file I/O tasks.
+  explicit ContentURLLoaderFactory(
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
+  ~ContentURLLoaderFactory() override;
+
+ private:
+  // network::mojom::URLLoaderFactory:
+  void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const network::ResourceRequest& request,
+                            network::mojom::URLLoaderClientPtr client,
+                            const net::MutableNetworkTrafficAnnotationTag&
+                                traffic_annotation) override;
+  void Clone(network::mojom::URLLoaderFactoryRequest loader) override;
+
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+  mojo::BindingSet<network::mojom::URLLoaderFactory> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(ContentURLLoaderFactory);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_ANDROID_CONTENT_URL_LOADER_FACTORY_H_
diff --git a/content/browser/android/url_request_content_job.h b/content/browser/android/url_request_content_job.h
index 40a97470..e389fdd3 100644
--- a/content/browser/android/url_request_content_job.h
+++ b/content/browser/android/url_request_content_job.h
@@ -31,6 +31,9 @@
 namespace content {
 
 // A request job that handles reading content URIs
+//
+// Note that when the Network Service is enabled, ContentUrlLoaderFactory is
+// used instead.
 class CONTENT_EXPORT URLRequestContentJob : public net::URLRequestJob {
  public:
   URLRequestContentJob(
diff --git a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
index f5c9e11..ff4993c 100644
--- a/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
+++ b/content/browser/background_fetch/background_fetch_data_manager_unittest.cc
@@ -831,7 +831,8 @@
     CreateRegistration(registration_id,
                        std::vector<ServiceWorkerFetchRequest>(),
                        BackgroundFetchOptions(), SkBitmap(), &error);
-    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::QUOTA_EXCEEDED);
+    ASSERT_EQ(error,
+              blink::mojom::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED);
   }
 
   // The registration should also fail for the other Service Worker.
@@ -841,7 +842,8 @@
     CreateRegistration(registration_id,
                        std::vector<ServiceWorkerFetchRequest>(),
                        BackgroundFetchOptions(), SkBitmap(), &error);
-    ASSERT_EQ(error, blink::mojom::BackgroundFetchError::QUOTA_EXCEEDED);
+    ASSERT_EQ(error,
+              blink::mojom::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED);
   }
 }
 
diff --git a/content/browser/background_fetch/storage/create_metadata_task.cc b/content/browser/background_fetch/storage/create_metadata_task.cc
index 8695617..ff706e7 100644
--- a/content/browser/background_fetch/storage/create_metadata_task.cc
+++ b/content/browser/background_fetch/storage/create_metadata_task.cc
@@ -156,8 +156,8 @@
 
   DCHECK_EQ(error, blink::mojom::BackgroundFetchError::NONE);
   if (!can_create) {
-    // TODO(crbug.com/889401): Report a more descriptive storage error.
-    FinishWithError(blink::mojom::BackgroundFetchError::QUOTA_EXCEEDED);
+    FinishWithError(
+        blink::mojom::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED);
     return;
   }
 
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index 3d105841..beaf2b8 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -13,7 +13,6 @@
 #include "base/lazy_instance.h"
 #include "base/observer_list.h"
 #include "content/browser/devtools/devtools_manager.h"
-#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/forwarding_agent_host.h"
 #include "content/browser/devtools/protocol/page.h"
 #include "content/browser/devtools/protocol/security_handler.h"
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 957fcf1..1db75042 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -15,6 +15,7 @@
 #include "base/process/kill.h"
 #include "content/browser/devtools/devtools_io_context.h"
 #include "content/browser/devtools/devtools_renderer_channel.h"
+#include "content/browser/devtools/devtools_session.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/certificate_request_result_type.h"
 #include "content/public/browser/devtools_agent_host.h"
@@ -23,7 +24,6 @@
 namespace content {
 
 class BrowserContext;
-class DevToolsSession;
 class TargetRegistry;
 
 // Describes interface for managing devtools agents from the browser process.
@@ -59,6 +59,19 @@
 
   bool Inspect();
 
+  template <typename Handler>
+  std::vector<Handler*> HandlersByName(const std::string& name) {
+    std::vector<Handler*> result;
+    if (sessions_.empty())
+      return result;
+    for (DevToolsSession* session : sessions_) {
+      auto it = session->handlers().find(name);
+      if (it != session->handlers().end())
+        result.push_back(static_cast<Handler*>(it->second.get()));
+    }
+    return result;
+  }
+
  protected:
   DevToolsAgentHostImpl(const std::string& id);
   ~DevToolsAgentHostImpl() override;
@@ -88,7 +101,6 @@
 
  private:
   friend class DevToolsAgentHost;  // for static methods
-  friend class DevToolsSession;
   friend class TargetRegistry;  // for subtarget management
   friend class DevToolsRendererChannel;
 
diff --git a/content/browser/devtools/devtools_renderer_channel.cc b/content/browser/devtools/devtools_renderer_channel.cc
index 0793d766..6a88fb48 100644
--- a/content/browser/devtools/devtools_renderer_channel.cc
+++ b/content/browser/devtools/devtools_renderer_channel.cc
@@ -6,6 +6,7 @@
 
 #include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/public/common/child_process_host.h"
 #include "ui/gfx/geometry/point.h"
 
@@ -23,14 +24,19 @@
   agent_ptr_ = std::move(agent_ptr);
   process_id_ = process_id;
   frame_host_ = frame_host;
-  for (DevToolsSession* session : owner_->sessions())
-    session->AttachToAgent(agent_ptr_.get(), process_id_, frame_host_);
+  for (DevToolsSession* session : owner_->sessions()) {
+    for (auto& pair : session->handlers())
+      pair.second->SetRenderer(process_id_, frame_host_);
+    session->AttachToAgent(agent_ptr_.get());
+  }
 }
 
 void DevToolsRendererChannel::AttachSession(DevToolsSession* session) {
   if (!agent_ptr_)
     owner_->UpdateRendererChannel(true /* force */);
-  session->AttachToAgent(agent_ptr_.get(), process_id_, frame_host_);
+  for (auto& pair : session->handlers())
+    pair.second->SetRenderer(process_id_, frame_host_);
+  session->AttachToAgent(agent_ptr_.get());
 }
 
 void DevToolsRendererChannel::InspectElement(const gfx::Point& point) {
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index c306b8b..fa29cf6a 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -7,11 +7,11 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "content/browser/devtools/devtools_manager.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/protocol.h"
 #include "content/browser/devtools/render_frame_devtools_agent_host.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/browser/devtools_manager_delegate.h"
-#include "content/public/common/child_process_host.h"
 
 namespace content {
 
@@ -36,8 +36,6 @@
     : binding_(this),
       agent_host_(agent_host),
       client_(client),
-      process_host_id_(ChildProcessHost::kInvalidUniqueID),
-      host_(nullptr),
       dispatcher_(new protocol::UberDispatcher(this)),
       weak_factory_(this) {}
 
@@ -65,14 +63,7 @@
   browser_only_ = browser_only;
 }
 
-void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent,
-                                    int process_host_id,
-                                    RenderFrameHostImpl* frame_host) {
-  process_host_id_ = process_host_id;
-  host_ = frame_host;
-  for (auto& pair : handlers_)
-    pair.second->SetRenderer(process_host_id_, host_);
-
+void DevToolsSession::AttachToAgent(blink::mojom::DevToolsAgent* agent) {
   if (!agent) {
     binding_.Close();
     session_ptr_.reset();
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h
index 43d3a71ab..b845a54 100644
--- a/content/browser/devtools/devtools_session.h
+++ b/content/browser/devtools/devtools_session.h
@@ -11,15 +11,18 @@
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
 #include "base/values.h"
-#include "content/browser/devtools/devtools_agent_host_impl.h"
-#include "content/browser/devtools/protocol/devtools_domain_handler.h"
+#include "content/browser/devtools/protocol/forward.h"
 #include "mojo/public/cpp/bindings/associated_binding.h"
 #include "third_party/blink/public/web/devtools_agent.mojom.h"
 
 namespace content {
 
 class DevToolsAgentHostClient;
-class RenderFrameHostImpl;
+class DevToolsAgentHostImpl;
+
+namespace protocol {
+class DevToolsDomainHandler;
+}
 
 class DevToolsSession : public protocol::FrontendChannel,
                         public blink::mojom::DevToolsSessionHost {
@@ -29,38 +32,25 @@
   ~DevToolsSession() override;
   void Dispose();
 
-  DevToolsAgentHost* agent_host() { return agent_host_; };
+  DevToolsAgentHostImpl* agent_host() { return agent_host_; };
   DevToolsAgentHostClient* client() { return client_; };
 
   // Browser-only sessions do not talk to mojom::DevToolsAgent, but instead
   // handle all protocol messages locally in the browser process.
   void SetBrowserOnly(bool browser_only);
-
   void AddHandler(std::unique_ptr<protocol::DevToolsDomainHandler> handler);
 
-  void AttachToAgent(blink::mojom::DevToolsAgent* agent,
-                     int process_host_id,
-                     RenderFrameHostImpl* frame_host);
+  void AttachToAgent(blink::mojom::DevToolsAgent* agent);
   void DispatchProtocolMessage(
       const std::string& message,
       std::unique_ptr<base::DictionaryValue> parsed_message);
   void SuspendSendingMessagesToAgent();
   void ResumeSendingMessagesToAgent();
 
-  template <typename Handler>
-  static std::vector<Handler*> HandlersForAgentHost(
-      DevToolsAgentHostImpl* agent_host,
-      const std::string& name) {
-    std::vector<Handler*> result;
-    if (agent_host->sessions().empty())
-      return result;
-    for (DevToolsSession* session : agent_host->sessions()) {
-      auto it = session->handlers_.find(name);
-      if (it != session->handlers_.end())
-        result.push_back(static_cast<Handler*>(it->second.get()));
-    }
-    return result;
-  }
+  using HandlersMap =
+      base::flat_map<std::string,
+                     std::unique_ptr<protocol::DevToolsDomainHandler>>;
+  HandlersMap& handlers() { return handlers_; }
 
  private:
   void SendResponse(std::unique_ptr<base::DictionaryValue> response);
@@ -100,10 +90,7 @@
   DevToolsAgentHostImpl* agent_host_;
   DevToolsAgentHostClient* client_;
   bool browser_only_ = false;
-  base::flat_map<std::string, std::unique_ptr<protocol::DevToolsDomainHandler>>
-      handlers_;
-  int process_host_id_;
-  RenderFrameHostImpl* host_;
+  HandlersMap handlers_;
   std::unique_ptr<protocol::UberDispatcher> dispatcher_;
 
   // These messages were queued after suspending, not sent to the agent,
diff --git a/content/browser/devtools/protocol/emulation_handler.cc b/content/browser/devtools/protocol/emulation_handler.cc
index 9a2cc5f..8df358c 100644
--- a/content/browser/devtools/protocol/emulation_handler.cc
+++ b/content/browser/devtools/protocol/emulation_handler.cc
@@ -8,7 +8,7 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
-#include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/input/touch_emulator.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -69,8 +69,8 @@
 // static
 std::vector<EmulationHandler*> EmulationHandler::ForAgentHost(
     DevToolsAgentHostImpl* host) {
-  return DevToolsSession::HandlersForAgentHost<EmulationHandler>(
-      host, Emulation::Metainfo::domainName);
+  return host->HandlersByName<EmulationHandler>(
+      Emulation::Metainfo::domainName);
 }
 
 void EmulationHandler::SetRenderer(int process_host_id,
diff --git a/content/browser/devtools/protocol/input_handler.cc b/content/browser/devtools/protocol/input_handler.cc
index d89856b0..d6fbc01 100644
--- a/content/browser/devtools/protocol/input_handler.cc
+++ b/content/browser/devtools/protocol/input_handler.cc
@@ -10,7 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
-#include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/protocol/native_input_event_builder.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/input/touch_emulator.h"
@@ -414,8 +414,7 @@
 // static
 std::vector<InputHandler*> InputHandler::ForAgentHost(
     DevToolsAgentHostImpl* host) {
-  return DevToolsSession::HandlersForAgentHost<InputHandler>(
-      host, Input::Metainfo::domainName);
+  return host->HandlersByName<InputHandler>(Input::Metainfo::domainName);
 }
 
 void InputHandler::SetRenderer(int process_host_id,
diff --git a/content/browser/devtools/protocol/inspector_handler.cc b/content/browser/devtools/protocol/inspector_handler.cc
index ae8e11f..31eb6d4 100644
--- a/content/browser/devtools/protocol/inspector_handler.cc
+++ b/content/browser/devtools/protocol/inspector_handler.cc
@@ -4,7 +4,7 @@
 
 #include "content/browser/devtools/protocol/inspector_handler.h"
 
-#include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 
 namespace content {
@@ -21,8 +21,8 @@
 // static
 std::vector<InspectorHandler*> InspectorHandler::ForAgentHost(
     DevToolsAgentHostImpl* host) {
-  return DevToolsSession::HandlersForAgentHost<InspectorHandler>(
-      host, Inspector::Metainfo::domainName);
+  return host->HandlersByName<InspectorHandler>(
+      Inspector::Metainfo::domainName);
 }
 
 void InspectorHandler::Wire(UberDispatcher* dispatcher) {
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index df186ce..e324470 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -19,9 +19,9 @@
 #include "base/task/post_task.h"
 #include "base/time/time.h"
 #include "content/browser/background_sync/background_sync_manager.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/devtools_interceptor_controller.h"
 #include "content/browser/devtools/devtools_io_context.h"
-#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/devtools_stream_pipe.h"
 #include "content/browser/devtools/devtools_url_loader_interceptor.h"
 #include "content/browser/devtools/protocol/page.h"
@@ -987,8 +987,7 @@
 // static
 std::vector<NetworkHandler*> NetworkHandler::ForAgentHost(
     DevToolsAgentHostImpl* host) {
-  return DevToolsSession::HandlersForAgentHost<NetworkHandler>(
-      host, Network::Metainfo::domainName);
+  return host->HandlersByName<NetworkHandler>(Network::Metainfo::domainName);
 }
 
 void NetworkHandler::Wire(UberDispatcher* dispatcher) {
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 83033ea..5f2d301 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -23,7 +23,7 @@
 #include "base/task/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/protocol/devtools_download_manager_delegate.h"
 #include "content/browser/devtools/protocol/devtools_download_manager_helper.h"
 #include "content/browser/devtools/protocol/emulation_handler.h"
@@ -242,8 +242,7 @@
 // static
 std::vector<PageHandler*> PageHandler::ForAgentHost(
     DevToolsAgentHostImpl* host) {
-  return DevToolsSession::HandlersForAgentHost<PageHandler>(
-      host, Page::Metainfo::domainName);
+  return host->HandlersByName<PageHandler>(Page::Metainfo::domainName);
 }
 
 void PageHandler::SetRenderer(int process_host_id,
diff --git a/content/browser/devtools/protocol/security_handler.cc b/content/browser/devtools/protocol/security_handler.cc
index bdc3c63..29e074d 100644
--- a/content/browser/devtools/protocol/security_handler.cc
+++ b/content/browser/devtools/protocol/security_handler.cc
@@ -10,7 +10,7 @@
 #include <vector>
 
 #include "base/base64.h"
-#include "content/browser/devtools/devtools_session.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
@@ -104,8 +104,7 @@
 // static
 std::vector<SecurityHandler*> SecurityHandler::ForAgentHost(
     DevToolsAgentHostImpl* host) {
-  return DevToolsSession::HandlersForAgentHost<SecurityHandler>(
-      host, Security::Metainfo::domainName);
+  return host->HandlersByName<SecurityHandler>(Security::Metainfo::domainName);
 }
 
 SecurityHandler::SecurityHandler()
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index 9d63cfa..3e03ef91 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -13,8 +13,8 @@
 #include "base/values.h"
 #include "build/build_config.h"
 #include "content/browser/devtools/browser_devtools_agent_host.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/devtools_manager.h"
-#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/target_registry.h"
 #include "content/browser/frame_host/navigation_handle_impl.h"
 #include "content/public/browser/browser_context.h"
@@ -438,8 +438,7 @@
 // static
 std::vector<TargetHandler*> TargetHandler::ForAgentHost(
     DevToolsAgentHostImpl* host) {
-  return DevToolsSession::HandlersForAgentHost<TargetHandler>(
-      host, Target::Metainfo::domainName);
+  return host->HandlersByName<TargetHandler>(Target::Metainfo::domainName);
 }
 
 void TargetHandler::Wire(UberDispatcher* dispatcher) {
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index 590ebdf..fd1dcd8 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -25,9 +25,9 @@
 #include "base/trace_event/trace_event_impl.h"
 #include "base/trace_event/tracing_agent.h"
 #include "components/tracing/common/trace_startup_config.h"
+#include "content/browser/devtools/devtools_agent_host_impl.h"
 #include "content/browser/devtools/devtools_frame_trace_recorder.h"
 #include "content/browser/devtools/devtools_io_context.h"
-#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/devtools_stream_file.h"
 #include "content/browser/devtools/devtools_traceable_screenshot.h"
 #include "content/browser/devtools/devtools_video_consumer.h"
@@ -237,8 +237,7 @@
 // static
 std::vector<TracingHandler*> TracingHandler::ForAgentHost(
     DevToolsAgentHostImpl* host) {
-  return DevToolsSession::HandlersForAgentHost<TracingHandler>(
-      host, Tracing::Metainfo::domainName);
+  return host->HandlersByName<TracingHandler>(Tracing::Metainfo::domainName);
 }
 
 void TracingHandler::SetRenderer(int process_host_id,
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index ea4d8ee..8ae226b 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -560,8 +560,6 @@
     size_t first_byte_to_send = 0;
     size_t total_bytes_to_send = static_cast<size_t>(info.size);
 
-    total_bytes_written_ = static_cast<size_t>(info.size);
-
     if (byte_range.IsValid()) {
       first_byte_to_send =
           static_cast<size_t>(byte_range.first_byte_position());
@@ -570,6 +568,8 @@
           first_byte_to_send + 1;
     }
 
+    total_bytes_written_ = static_cast<size_t>(total_bytes_to_send);
+
     head.content_length = base::saturated_cast<int64_t>(total_bytes_to_send);
 
     if (first_byte_to_send < initial_read_size) {
@@ -677,7 +677,9 @@
   network::mojom::URLLoaderClientPtr client_;
   std::unique_ptr<RedirectData> redirect_data_;
 
-  // In case of successful loads, this holds the total of bytes written.
+  // In case of successful loads, this holds the total number of bytes written
+  // to the response (this may be smaller than the total size of the file when
+  // a byte range was requested).
   // It is used to set some of the URLLoaderCompletionStatus data passed back
   // to the URLLoaderClients (eg SimpleURLLoader).
   size_t total_bytes_written_ = 0;
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index d700994..0184681a 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -181,6 +181,7 @@
 #include "url/url_constants.h"
 
 #if defined(OS_ANDROID)
+#include "content/browser/android/content_url_loader_factory.h"
 #include "content/browser/android/java_interfaces_impl.h"
 #include "content/browser/frame_host/render_frame_host_android.h"
 #include "content/public/browser/android/java_interfaces.h"
@@ -4074,6 +4075,18 @@
                                                 std::move(file_factory));
     }
 
+#if defined(OS_ANDROID)
+    if (common_params.url.SchemeIs(url::kContentScheme)) {
+      // Only content:// URLs can load content:// subresources
+      auto content_factory = std::make_unique<ContentURLLoaderFactory>(
+          base::CreateSequencedTaskRunnerWithTraits(
+              {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+               base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+      non_network_url_loader_factories_.emplace(url::kContentScheme,
+                                                std::move(content_factory));
+    }
+#endif
+
     StoragePartition* partition =
         BrowserContext::GetStoragePartition(browser_context, GetSiteInstance());
     std::string storage_domain;
diff --git a/content/browser/gpu/compositor_util.cc b/content/browser/gpu/compositor_util.cc
index 9bcf1916..c4a4153 100644
--- a/content/browser/gpu/compositor_util.cc
+++ b/content/browser/gpu/compositor_util.cc
@@ -177,6 +177,16 @@
        "Native GpuMemoryBuffers have been disabled, either via about:flags or "
        "command line.",
        true, true},
+      {"surface_control",
+       SafeGetFeatureStatus(gpu_feature_info,
+                            gpu::GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL),
+#if defined(OS_ANDROID)
+       !base::FeatureList::IsEnabled(features::kAndroidSurfaceControl),
+#else
+       false,
+#endif
+       "Surface Control has been disabled by Finch trial or command line.",
+       false, false},
       {"surface_synchronization", gpu::kGpuFeatureStatusEnabled,
        !features::IsSurfaceSynchronizationEnabled(),
        "Surface synchronization has been disabled by Finch trial or command "
diff --git a/content/browser/gpu/compositor_util.h b/content/browser/gpu/compositor_util.h
index e9ed209..c7155e6 100644
--- a/content/browser/gpu/compositor_util.h
+++ b/content/browser/gpu/compositor_util.h
@@ -37,9 +37,6 @@
 // Returns true if main thread can be pipelined with activation.
 CONTENT_EXPORT bool IsMainFrameBeforeActivationEnabled();
 
-// Returns true if image animations should run in the compositor.
-CONTENT_EXPORT bool IsCompositorImageAnimationEnabled();
-
 CONTENT_EXPORT std::unique_ptr<base::DictionaryValue> GetFeatureStatus();
 CONTENT_EXPORT std::unique_ptr<base::ListValue> GetProblems();
 CONTENT_EXPORT std::vector<std::string> GetDriverBugWorkarounds();
diff --git a/content/browser/loader/navigation_url_loader_impl.cc b/content/browser/loader/navigation_url_loader_impl.cc
index 286b17e..7ce9a48 100644
--- a/content/browser/loader/navigation_url_loader_impl.cc
+++ b/content/browser/loader/navigation_url_loader_impl.cc
@@ -16,6 +16,7 @@
 #include "base/stl_util.h"
 #include "base/task/post_task.h"
 #include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
 #include "components/download/public/common/download_stats.h"
 #include "content/browser/appcache/appcache_navigation_handle.h"
 #include "content/browser/appcache/appcache_navigation_handle_core.h"
@@ -88,6 +89,10 @@
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 #include "url/gurl.h"
 
+#if defined(OS_ANDROID)
+#include "content/browser/android/content_url_loader_factory.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -1610,6 +1615,15 @@
           base::CreateSequencedTaskRunnerWithTraits(
               {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
                base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+
+#if defined(OS_ANDROID)
+  non_network_url_loader_factories_[url::kContentScheme] =
+      std::make_unique<ContentURLLoaderFactory>(
+          base::CreateSequencedTaskRunnerWithTraits(
+              {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+               base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+#endif
+
   std::set<std::string> known_schemes;
   for (auto& iter : non_network_url_loader_factories_)
     known_schemes.insert(iter.first);
diff --git a/content/browser/network_service_browsertest.cc b/content/browser/network_service_browsertest.cc
index 3abc4d3..85ee344 100644
--- a/content/browser/network_service_browsertest.cc
+++ b/content/browser/network_service_browsertest.cc
@@ -23,8 +23,11 @@
 #include "content/public/test/test_utils.h"
 #include "content/shell/browser/shell.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/http/http_response_headers.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/application_status_listener.h"
@@ -226,6 +229,32 @@
   EXPECT_FALSE(FetchResource(file_url));
 }
 
+IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest,
+                       SimpleUrlLoader_NoAuthWhenNoWebContents) {
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = embedded_test_server()->GetURL("/auth-basic?password=");
+  auto loader = network::SimpleURLLoader::Create(std::move(request),
+                                                 TRAFFIC_ANNOTATION_FOR_TESTS);
+  auto loader_factory = BrowserContext::GetDefaultStoragePartition(
+                            shell()->web_contents()->GetBrowserContext())
+                            ->GetURLLoaderFactoryForBrowserProcess();
+  scoped_refptr<net::HttpResponseHeaders> headers;
+  base::RunLoop loop;
+  loader->DownloadHeadersOnly(
+      loader_factory.get(),
+      base::BindOnce(
+          [](base::OnceClosure quit_closure,
+             scoped_refptr<net::HttpResponseHeaders>* rh_out,
+             scoped_refptr<net::HttpResponseHeaders> rh_in) {
+            *rh_out = rh_in;
+            std::move(quit_closure).Run();
+          },
+          loop.QuitClosure(), &headers));
+  loop.Run();
+  ASSERT_TRUE(headers.get());
+  ASSERT_EQ(headers->response_code(), 401);
+}
+
 #if defined(OS_ANDROID)
 IN_PROC_BROWSER_TEST_F(NetworkServiceBrowserTest,
                        HttpCacheWrittenToDiskOnApplicationStateChange) {
diff --git a/content/browser/network_service_client.cc b/content/browser/network_service_client.cc
index 7edddd1..3b82754 100644
--- a/content/browser/network_service_client.cc
+++ b/content/browser/network_service_client.cc
@@ -340,8 +340,7 @@
                  : base::Bind(WebContents::FromFrameTreeNodeId, routing_id);
 
   if (!web_contents_getter.Run()) {
-    std::move(auth_challenge_responder)
-        ->OnAuthCredentials(net::AuthCredentials());
+    std::move(auth_challenge_responder)->OnAuthCredentials(base::nullopt);
     return;
   }
 
diff --git a/content/browser/network_service_instance.cc b/content/browser/network_service_instance.cc
index 7b7dadb..aa19106 100644
--- a/content/browser/network_service_instance.cc
+++ b/content/browser/network_service_instance.cc
@@ -157,6 +157,13 @@
   return g_network_connection_tracker;
 }
 
+void GetNetworkConnectionTrackerFromUIThread(
+    base::OnceCallback<void(network::NetworkConnectionTracker*)> callback) {
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, {BrowserThread::UI, base::TaskPriority::BEST_EFFORT},
+      base::BindOnce(&GetNetworkConnectionTracker), std::move(callback));
+}
+
 void SetNetworkConnectionTrackerForTesting(
     network::NetworkConnectionTracker* network_connection_tracker) {
   if (g_network_connection_tracker != network_connection_tracker) {
diff --git a/content/browser/ns_view_bridge_factory_impl.mm b/content/browser/ns_view_bridge_factory_impl.mm
index 295191f2..5230e9f 100644
--- a/content/browser/ns_view_bridge_factory_impl.mm
+++ b/content/browser/ns_view_bridge_factory_impl.mm
@@ -10,6 +10,7 @@
 #include "base/no_destructor.h"
 #include "content/browser/renderer_host/render_widget_host_ns_view_bridge_local.h"
 #include "content/browser/web_contents/web_contents_ns_view_bridge.h"
+#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 
 namespace content {
 
@@ -21,7 +22,8 @@
 
 void NSViewBridgeFactoryImpl::BindRequest(
     mojom::NSViewBridgeFactoryAssociatedRequest request) {
-  binding_.Bind(std::move(request));
+  binding_.Bind(std::move(request),
+                ui::WindowResizeHelperMac::Get()->task_runner());
 }
 
 void NSViewBridgeFactoryImpl::CreateRenderWidgetHostNSViewBridge(
diff --git a/content/browser/renderer_host/render_widget_host_ns_view_bridge_local.mm b/content/browser/renderer_host/render_widget_host_ns_view_bridge_local.mm
index c9351780..f2f17542 100644
--- a/content/browser/renderer_host/render_widget_host_ns_view_bridge_local.mm
+++ b/content/browser/renderer_host/render_widget_host_ns_view_bridge_local.mm
@@ -9,6 +9,7 @@
 #include "content/browser/renderer_host/render_widget_host_ns_view_client_helper.h"
 #include "content/common/cursors/webcursor.h"
 #import "skia/ext/skia_utils_mac.h"
+#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #import "ui/base/cocoa/animation_utils.h"
 #include "ui/base/cocoa/ns_view_ids.h"
 #include "ui/display/screen.h"
@@ -28,7 +29,8 @@
     mojom::RenderWidgetHostNSViewClientAssociatedPtr client,
     mojom::RenderWidgetHostNSViewBridgeAssociatedRequest bridge_request)
     : remote_client_(std::move(client)), binding_(this) {
-  binding_.Bind(std::move(bridge_request));
+  binding_.Bind(std::move(bridge_request),
+                ui::WindowResizeHelperMac::Get()->task_runner());
   // This object will be destroyed when its connection is closed.
   binding_.set_connection_error_handler(
       base::BindOnce(&RenderWidgetHostNSViewBridgeLocal::OnConnectionError,
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 97a34da..b537b5f 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1184,7 +1184,7 @@
 }
 
 void RenderWidgetHostViewAura::SetMainFrameAXTreeID(ui::AXTreeID id) {
-  window_->SetProperty(ui::kChildAXTreeID, new ui::AXTreeID(id));
+  window_->SetProperty(ui::kChildAXTreeID, new std::string(id.ToString()));
 }
 
 bool RenderWidgetHostViewAura::LockMouse() {
diff --git a/content/browser/resources/gpu/info_view.js b/content/browser/resources/gpu/info_view.js
index 122f2e8..780b52a 100644
--- a/content/browser/resources/gpu/info_view.js
+++ b/content/browser/resources/gpu/info_view.js
@@ -235,6 +235,7 @@
         'native_gpu_memory_buffers': 'Native GpuMemoryBuffers',
         'protected_video_decode': 'Hardware Protected Video Decode',
         'surface_synchronization': 'Surface Synchronization',
+        'surface_control': 'Surface Control',
         'vpx_decode': 'VPx Video Decode',
         'webgl2': 'WebGL2',
         'viz_display_compositor': 'Viz Service Display Compositor',
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc
index 8401b7c..a17f803 100644
--- a/content/browser/utility_process_host.cc
+++ b/content/browser/utility_process_host.cc
@@ -102,8 +102,17 @@
   }
 
   bool DisableDefaultPolicy() override {
-    return sandbox_type_ == service_manager::SANDBOX_TYPE_XRCOMPOSITING &&
-           base::FeatureList::IsEnabled(service_manager::features::kXRSandbox);
+    switch (sandbox_type_) {
+      case service_manager::SANDBOX_TYPE_AUDIO:
+        // Default policy is disabled for audio process to allow audio drivers
+        // to read device properties (https://crbug.com/883326).
+        return true;
+      case service_manager::SANDBOX_TYPE_XRCOMPOSITING:
+        return base::FeatureList::IsEnabled(
+            service_manager::features::kXRSandbox);
+      default:
+        return false;
+    }
   }
 
   bool ShouldLaunchElevated() override {
diff --git a/content/browser/web_contents/web_contents_ns_view_bridge.mm b/content/browser/web_contents/web_contents_ns_view_bridge.mm
index 109e175..90181ae 100644
--- a/content/browser/web_contents/web_contents_ns_view_bridge.mm
+++ b/content/browser/web_contents/web_contents_ns_view_bridge.mm
@@ -4,6 +4,8 @@
 
 #include "content/browser/web_contents/web_contents_ns_view_bridge.h"
 
+#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
+
 namespace content {
 
 WebContentsNSViewBridge::WebContentsNSViewBridge(
@@ -11,7 +13,8 @@
     mojom::WebContentsNSViewClientAssociatedPtr client,
     mojom::WebContentsNSViewBridgeAssociatedRequest bridge_request)
     : client_(std::move(client)), binding_(this) {
-  binding_.Bind(std::move(bridge_request));
+  binding_.Bind(std::move(bridge_request),
+                ui::WindowResizeHelperMac::Get()->task_runner());
   // This object will be destroyed when its connection is closed.
   binding_.set_connection_error_handler(base::BindOnce(
       &WebContentsNSViewBridge::OnConnectionError, base::Unretained(this)));
diff --git a/content/public/browser/authenticator_request_client_delegate.cc b/content/public/browser/authenticator_request_client_delegate.cc
index 8d77193..72a0ab7 100644
--- a/content/public/browser/authenticator_request_client_delegate.cc
+++ b/content/public/browser/authenticator_request_client_delegate.cc
@@ -66,4 +66,8 @@
 void AuthenticatorRequestClientDelegate::FidoAuthenticatorRemoved(
     base::StringPiece device_id) {}
 
+void AuthenticatorRequestClientDelegate::FidoAuthenticatorIdChanged(
+    base::StringPiece old_authenticator_id,
+    std::string new_authenticator_id) {}
+
 }  // namespace content
diff --git a/content/public/browser/authenticator_request_client_delegate.h b/content/public/browser/authenticator_request_client_delegate.h
index 4f11a73..b4be9c0 100644
--- a/content/public/browser/authenticator_request_client_delegate.h
+++ b/content/public/browser/authenticator_request_client_delegate.h
@@ -15,6 +15,10 @@
 #include "device/fido/fido_request_handler_base.h"
 #include "device/fido/fido_transport_protocol.h"
 
+#if defined(OS_MACOSX)
+#include "device/fido/mac/authenticator_config.h"
+#endif
+
 namespace device {
 class FidoAuthenticator;
 }
@@ -80,18 +84,7 @@
   virtual bool IsFocused();
 
 #if defined(OS_MACOSX)
-  struct TouchIdAuthenticatorConfig {
-    // The keychain-access-group value used for WebAuthn credentials
-    // stored in the macOS keychain by the built-in Touch ID
-    // authenticator. For more information on this, refer to
-    // |device::fido::TouchIdAuthenticator|.
-    std::string keychain_access_group;
-    // The secret used to derive key material when encrypting WebAuthn
-    // credential metadata for storage in the macOS keychain. Chrome returns
-    // different secrets for each user profile in order to logically separate
-    // credentials per profile.
-    std::string metadata_secret;
-  };
+  using TouchIdAuthenticatorConfig = device::fido::mac::AuthenticatorConfig;
 
   // Returns configuration data for the built-in Touch ID platform
   // authenticator. May return nullopt if the authenticator is not used or not
@@ -122,6 +115,8 @@
   void FidoAuthenticatorAdded(
       const device::FidoAuthenticator& authenticator) override;
   void FidoAuthenticatorRemoved(base::StringPiece device_id) override;
+  void FidoAuthenticatorIdChanged(base::StringPiece old_authenticator_id,
+                                  std::string new_authenticator_id) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(AuthenticatorRequestClientDelegate);
diff --git a/content/public/browser/gpu_utils.cc b/content/public/browser/gpu_utils.cc
index 84007d7..75255050 100644
--- a/content/public/browser/gpu_utils.cc
+++ b/content/public/browser/gpu_utils.cc
@@ -11,10 +11,12 @@
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
 #include "cc/base/switches.h"
+#include "components/viz/common/features.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "gpu/command_buffer/service/service_utils.h"
+#include "gpu/config/gpu_finch_features.h"
 #include "gpu/config/gpu_switches.h"
 #include "media/media_buildflags.h"
 
@@ -47,6 +49,17 @@
 
 namespace content {
 
+bool ShouldEnableAndroidSurfaceControl(const base::CommandLine& cmd_line) {
+#if !defined(OS_ANDROID)
+  return false;
+#else
+  if (!base::FeatureList::IsEnabled(features::kVizDisplayCompositor))
+    return false;
+
+  return base::FeatureList::IsEnabled(features::kAndroidSurfaceControl);
+#endif
+}
+
 const gpu::GpuPreferences GetGpuPreferencesFromCommandLine() {
   DCHECK(base::CommandLine::InitializedForCurrentProcess());
   const base::CommandLine* command_line =
@@ -105,6 +118,9 @@
   gpu_preferences.enable_gpu_benchmarking_extension =
       command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking);
 
+  gpu_preferences.enable_android_surface_control =
+      ShouldEnableAndroidSurfaceControl(*command_line);
+
   // Some of these preferences are set or adjusted in
   // GpuDataManagerImplPrivate::AppendGpuCommandLine.
   return gpu_preferences;
diff --git a/content/public/browser/network_service_instance.h b/content/public/browser/network_service_instance.h
index 69678a7..3a7402b 100644
--- a/content/public/browser/network_service_instance.h
+++ b/content/public/browser/network_service_instance.h
@@ -5,6 +5,7 @@
 #ifndef CONTENT_PUBLIC_BROWSER_NETWORK_SERVICE_INSTANCE_H_
 #define CONTENT_PUBLIC_BROWSER_NETWORK_SERVICE_INSTANCE_H_
 
+#include "base/callback.h"
 #include "content/common/content_export.h"
 
 namespace network {
@@ -52,6 +53,14 @@
 // Must only be called on the UI thread.
 CONTENT_EXPORT network::NetworkConnectionTracker* GetNetworkConnectionTracker();
 
+// Asynchronously calls the given callback with a NetworkConnectionTracker that
+// can be used to subscribe to network change events.
+//
+// This is a helper method for classes that can't easily call
+// GetNetworkConnectionTracker from the UI thread.
+CONTENT_EXPORT void GetNetworkConnectionTrackerFromUIThread(
+    base::OnceCallback<void(network::NetworkConnectionTracker*)> callback);
+
 // Sets the NetworkConnectionTracker instance to use. For testing only.
 // Must be called on the UI thread. Must be called before the first call to
 // GetNetworkConnectionTracker.
diff --git a/content/renderer/media/webrtc/mock_peer_connection_impl.cc b/content/renderer/media/webrtc/mock_peer_connection_impl.cc
index ee019112..efed2e4 100644
--- a/content/renderer/media/webrtc/mock_peer_connection_impl.cc
+++ b/content/renderer/media/webrtc/mock_peer_connection_impl.cc
@@ -144,6 +144,11 @@
   return stream_ids_;
 }
 
+std::vector<webrtc::RtpEncodingParameters> FakeRtpSender::init_send_encodings()
+    const {
+  return {};
+}
+
 webrtc::RtpParameters FakeRtpSender::GetParameters() {
   NOTIMPLEMENTED();
   return webrtc::RtpParameters();
diff --git a/content/renderer/media/webrtc/mock_peer_connection_impl.h b/content/renderer/media/webrtc/mock_peer_connection_impl.h
index 5d348e7..6db7876 100644
--- a/content/renderer/media/webrtc/mock_peer_connection_impl.h
+++ b/content/renderer/media/webrtc/mock_peer_connection_impl.h
@@ -33,6 +33,8 @@
   cricket::MediaType media_type() const override;
   std::string id() const override;
   std::vector<std::string> stream_ids() const override;
+  std::vector<webrtc::RtpEncodingParameters> init_send_encodings()
+      const override;
   webrtc::RtpParameters GetParameters() override;
   webrtc::RTCError SetParameters(
       const webrtc::RtpParameters& parameters) override;
diff --git a/content/renderer/media/webrtc/rtc_video_decoder.cc b/content/renderer/media/webrtc/rtc_video_decoder.cc
index 2cb2a0b..c42e15b2 100644
--- a/content/renderer/media/webrtc/rtc_video_decoder.cc
+++ b/content/renderer/media/webrtc/rtc_video_decoder.cc
@@ -347,7 +347,6 @@
     picture_buffers.push_back(media::PictureBuffer(next_picture_buffer_id_++,
                                                    size, ids, mailboxes,
                                                    texture_target, format));
-    picture_buffers_at_display_.emplace(picture_buffers.back().id(), 0);
     const bool inserted =
         assigned_picture_buffers_
             .insert(std::make_pair(picture_buffers.back().id(),
@@ -369,23 +368,17 @@
     return;
   }
 
+  media::PictureBuffer buffer_to_dismiss = it->second;
+  assigned_picture_buffers_.erase(it);
+
+  if (!picture_buffers_at_display_.count(id)) {
+    // We can delete the texture immediately as it's not being displayed.
+    for (const auto& texture_id : buffer_to_dismiss.client_texture_ids())
+      factories_->DeleteTexture(texture_id);
+    return;
+  }
   // Not destroying a texture in display in |picture_buffers_at_display_|.
   // Postpone deletion until after it's returned to us.
-  media::PictureBuffer::TextureIds texture_ids =
-      (it->second).client_texture_ids();
-  auto picture_buffer_it = picture_buffers_at_display_.find(id);
-  if (picture_buffer_it != picture_buffers_at_display_.end() &&
-      picture_buffer_it->second > 0) {
-    DCHECK(!textures_to_be_deleted_.count(id));
-    textures_to_be_deleted_[id] = texture_ids;
-  } else {
-    // Otherwise, we can delete the texture immediately.
-    for (const auto texture_id : texture_ids)
-      factories_->DeleteTexture(texture_id);
-    if (picture_buffer_it != picture_buffers_at_display_.end())
-      picture_buffers_at_display_.erase(picture_buffer_it);
-  }
-  assigned_picture_buffers_.erase(it);
 }
 
 void RTCVideoDecoder::PictureReady(const media::Picture& picture) {
@@ -428,8 +421,11 @@
     NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
     return;
   }
-
-  ++picture_buffers_at_display_[picture.picture_buffer_id()];
+  bool inserted = picture_buffers_at_display_
+                      .insert(std::make_pair(picture.picture_buffer_id(),
+                                             pb.client_texture_ids()))
+                      .second;
+  DCHECK(inserted);
 
   // Create a WebRTC video frame.
   webrtc::VideoFrame decoded_image(
@@ -728,20 +724,18 @@
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
   DVLOG(3) << "ReusePictureBuffer. id=" << picture_buffer_id;
 
-  auto picture_buffer_it = picture_buffers_at_display_.find(picture_buffer_id);
-  DCHECK(picture_buffer_it != picture_buffers_at_display_.end());
-  DCHECK_GT(picture_buffer_it->second, 0u);
-  --picture_buffer_it->second;
+  DCHECK(!picture_buffers_at_display_.empty());
+  PictureBufferTextureMap::iterator display_iterator =
+      picture_buffers_at_display_.find(picture_buffer_id);
+  const auto texture_ids = display_iterator->second;
+  DCHECK(display_iterator != picture_buffers_at_display_.end());
+  picture_buffers_at_display_.erase(display_iterator);
 
-  if (picture_buffer_it->second == 0) {
-    auto iter = textures_to_be_deleted_.find(picture_buffer_id);
-    if (iter != textures_to_be_deleted_.end()) {
-      // This picture was dismissed while in display, so we postponed deletion.
-      for (const auto id : iter->second)
-        factories_->DeleteTexture(id);
-      textures_to_be_deleted_.erase(iter);
-      return;
-    }
+  if (!assigned_picture_buffers_.count(picture_buffer_id)) {
+    // This picture was dismissed while in display, so we postponed deletion.
+    for (const auto& id : texture_ids)
+      factories_->DeleteTexture(id);
+    return;
   }
 
   // DestroyVDA() might already have been called.
@@ -787,8 +781,17 @@
 void RTCVideoDecoder::DestroyTextures() {
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
 
-  while (!assigned_picture_buffers_.empty())
-    DismissPictureBuffer(assigned_picture_buffers_.begin()->first);
+  // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since
+  // their textures may still be in use by the user of this RTCVideoDecoder.
+  for (const auto& picture_buffer_at_display : picture_buffers_at_display_)
+    assigned_picture_buffers_.erase(picture_buffer_at_display.first);
+
+  for (const auto& assigned_picture_buffer : assigned_picture_buffers_) {
+    for (const auto& id : assigned_picture_buffer.second.client_texture_ids())
+      factories_->DeleteTexture(id);
+  }
+
+  assigned_picture_buffers_.clear();
 }
 
 void RTCVideoDecoder::DestroyVDA() {
diff --git a/content/renderer/media/webrtc/rtc_video_decoder.h b/content/renderer/media/webrtc/rtc_video_decoder.h
index 188ee3f..4db50b3 100644
--- a/content/renderer/media/webrtc/rtc_video_decoder.h
+++ b/content/renderer/media/webrtc/rtc_video_decoder.h
@@ -246,20 +246,14 @@
 
   // A map from picture buffer IDs to texture-backed picture buffers.
   std::map<int32_t, media::PictureBuffer> assigned_picture_buffers_;
-  // The texture ids that should be destroyed but the buffer is still in
-  // |picture_buffers_at_display_|. It will be destroyed when the buffer is
-  // returned from display via ReusePictureBuffer().
-  std::map<int32_t /* picture_buffer_id */,
-           media::PictureBuffer::TextureIds /* texture_ids */>
-      textures_to_be_deleted_;
+
   // PictureBuffers given to us by VDA via PictureReady, which we sent forward
   // as VideoFrames to be rendered via read_cb_, and which will be returned
-  // to us via ReusePictureBuffer. Note that a picture buffer might be sent from
-  // VDA multiple times. Therefore we use map to track the number of times we
-  // passed the picture buffer for display.
-  std::map<int32_t /* picture_buffer_id */,
-           size_t /* num_times_sent_to_client */>
-      picture_buffers_at_display_;
+  // to us via ReusePictureBuffer.
+  typedef std::map<int32_t /* picture_buffer_id */,
+                   media::PictureBuffer::TextureIds /* texture ids */>
+      PictureBufferTextureMap;
+  PictureBufferTextureMap picture_buffers_at_display_;
 
   // The id that will be given to the next picture buffer.
   int32_t next_picture_buffer_id_;
diff --git a/content/renderer/pepper/pepper_video_decoder_host.cc b/content/renderer/pepper/pepper_video_decoder_host.cc
index 4671863..5201b8d 100644
--- a/content/renderer/pepper/pepper_video_decoder_host.cc
+++ b/content/renderer/pepper/pepper_video_decoder_host.cc
@@ -391,11 +391,7 @@
   PictureBufferMap::iterator it =
       picture_buffer_map_.find(picture.picture_buffer_id());
   DCHECK(it != picture_buffer_map_.end());
-  // VDA might send the same picture multiple times in VP9 video. However the
-  // Pepper client might not able to handle it. Therefore we just catch it here.
-  // https://crbug.com/755887
-  CHECK(it->second == PictureBufferState::ASSIGNED);
-
+  DCHECK(it->second == PictureBufferState::ASSIGNED);
   it->second = PictureBufferState::IN_USE;
 
   // Don't bother validating the visible rect, since the plugin process is less
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc
index cc2e74b..f35a2bec 100644
--- a/content/shell/browser/layout_test/blink_test_controller.cc
+++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -387,9 +387,16 @@
       test_url_.spec().find("compositing/") != std::string::npos;
   initial_size_ = Shell::GetShellDefaultSize();
   if (!main_window_) {
-    main_window_ = content::Shell::CreateNewWindow(browser_context, GURL(),
-                                                   nullptr, initial_size_);
+    main_window_ = content::Shell::CreateNewWindow(
+        browser_context, GURL(url::kAboutBlankURL), nullptr, initial_size_);
     WebContentsObserver::Observe(main_window_->web_contents());
+
+    // The render frame host is constructed before the call to
+    // WebContentsObserver::Observe, so we need to manually handle the creation
+    // of the new render frame host.
+    HandleNewRenderFrameHost(
+        main_window_->web_contents()->GetRenderViewHost()->GetMainFrame());
+
     if (is_devtools_protocol_test) {
       devtools_protocol_test_bindings_.reset(
           new DevToolsProtocolTestBindings(main_window_->web_contents()));
@@ -398,10 +405,24 @@
     default_prefs_ = main_window_->web_contents()
                          ->GetRenderViewHost()
                          ->GetWebkitPreferences();
-    if (is_devtools_js_test)
+    if (is_devtools_js_test) {
       LoadDevToolsJSTest();
-    else
-      main_window_->LoadURL(test_url_);
+    } else {
+      // Loading the URL will immediately start the layout test. Manually call
+      // LoadURLWithParams on the WebContents to avoid extraneous calls from
+      // content::Shell such as SetFocus(), which could race with the layout
+      // test.
+      NavigationController::LoadURLParams params(test_url_);
+
+      // Using PAGE_TRANSITION_LINK avoids a BrowsingInstance/process swap
+      // between layout tests.
+      params.transition_type =
+          ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
+
+      // Clear history to purge the prior navigation to about:blank.
+      params.should_clear_history_list = true;
+      main_window_->web_contents()->GetController().LoadURLWithParams(params);
+    }
   } else {
 #if defined(OS_MACOSX)
     // Shell::SizeTo is not implemented on all platforms.
@@ -490,6 +511,8 @@
   main_frame_dump_ = nullptr;
   waiting_for_pixel_results_ = false;
   waiting_for_main_frame_dump_ = false;
+  composite_all_frames_node_storage_.clear();
+  composite_all_frames_node_queue_ = std::queue<Node*>();
   weak_factory_.InvalidateWeakPtrs();
 
 #if defined(OS_ANDROID)
@@ -582,15 +605,12 @@
     if (base::CommandLine::ForCurrentProcess()->HasSwitch(
             switches::kEnableThreadedCompositing)) {
       rwhv->EnsureSurfaceSynchronizedForLayoutTest();
+      EnqueueSurfaceCopyRequest();
     } else {
-      CompositeAllFrames();
+      CompositeAllFramesThen(
+          base::BindOnce(&BlinkTestController::EnqueueSurfaceCopyRequest,
+                         weak_factory_.GetWeakPtr()));
     }
-
-    // Enqueue an image copy output request.
-    rwhv->CopyFromSurface(
-        gfx::Rect(), gfx::Size(),
-        base::BindOnce(&BlinkTestController::OnPixelDumpCaptured,
-                       weak_factory_.GetWeakPtr()));
   }
 
   RenderFrameHost* rfh = main_window_->web_contents()->GetMainFrame();
@@ -600,33 +620,71 @@
                      weak_factory_.GetWeakPtr()));
 }
 
-void BlinkTestController::CompositeAllFrames() {
-  std::vector<Node> node_storage;
-  Node* root = BuildFrameTree(main_window_->web_contents()->GetAllFrames(),
-                              &node_storage);
+// Enqueue an image copy output request.
+void BlinkTestController::EnqueueSurfaceCopyRequest() {
+  auto* rwhv = main_window_->web_contents()->GetRenderWidgetHostView();
+  rwhv->CopyFromSurface(
+      gfx::Rect(), gfx::Size(),
+      base::BindOnce(&BlinkTestController::OnPixelDumpCaptured,
+                     weak_factory_.GetWeakPtr()));
+}
 
-  mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_calls;
-  CompositeDepthFirst(root);
+void BlinkTestController::CompositeAllFramesThen(
+    base::OnceCallback<void()> callback) {
+  // Start with fresh storage and queue.
+  DCHECK(composite_all_frames_node_storage_.empty())
+      << "Attempted to composite twice in one test";
+  DCHECK(composite_all_frames_node_queue_.empty())
+      << "Attempted to composite twice in one test";
+  Node* root = BuildFrameTree(main_window_->web_contents()->GetAllFrames());
+  BuildDepthFirstQueue(root);
+  // Now asynchronously run through the node queue.
+  CompositeNodeQueueThen(std::move(callback));
+}
+
+void BlinkTestController::CompositeNodeQueueThen(
+    base::OnceCallback<void()> callback) {
+  RenderFrameHost* next_node_host;
+  do {
+    if (composite_all_frames_node_queue_.empty()) {
+      // Done with the queue - call the callback.
+      std::move(callback).Run();
+      return;
+    }
+    next_node_host =
+        composite_all_frames_node_queue_.front()->render_frame_host;
+    composite_all_frames_node_queue_.pop();
+  } while (!next_node_host || !next_node_host->IsRenderFrameLive());
+  GetLayoutTestControlPtr(next_node_host)
+      ->CompositeWithRaster(
+          base::BindOnce(&BlinkTestController::CompositeNodeQueueThen,
+                         weak_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void BlinkTestController::BuildDepthFirstQueue(Node* node) {
+  for (auto* child : node->children)
+    BuildDepthFirstQueue(child);
+  composite_all_frames_node_queue_.push(node);
 }
 
 BlinkTestController::Node* BlinkTestController::BuildFrameTree(
-    const std::vector<RenderFrameHost*>& frames,
-    std::vector<Node>* storage) const {
+    const std::vector<RenderFrameHost*>& frames) {
   // Ensure we don't reallocate during tree construction.
-  storage->reserve(frames.size());
+  composite_all_frames_node_storage_.reserve(frames.size());
 
   // Returns a Node for a given RenderFrameHost, or nullptr if doesn't exist.
-  auto node_for_frame = [storage](RenderFrameHost* rfh) {
+  auto node_for_frame = [this](RenderFrameHost* rfh) {
     auto it = std::find_if(
-        storage->begin(), storage->end(),
+        composite_all_frames_node_storage_.begin(),
+        composite_all_frames_node_storage_.end(),
         [rfh](const Node& node) { return node.render_frame_host == rfh; });
-    return it == storage->end() ? nullptr : &*it;
+    return it == composite_all_frames_node_storage_.end() ? nullptr : &*it;
   };
 
   // Add all of the frames to storage.
   for (auto* frame : frames) {
     DCHECK(!node_for_frame(frame)) << "Frame seen multiple times.";
-    storage->emplace_back(frame);
+    composite_all_frames_node_storage_.emplace_back(frame);
   }
 
   // Construct a tree rooted at |root|.
@@ -647,14 +705,6 @@
   return root;
 }
 
-void BlinkTestController::CompositeDepthFirst(Node* node) {
-  if (!node->render_frame_host->IsRenderFrameLive())
-    return;
-  for (auto* child : node->children)
-    CompositeDepthFirst(child);
-  GetLayoutTestControlPtr(node->render_frame_host)->CompositeWithRaster();
-}
-
 bool BlinkTestController::IsMainWindow(WebContents* web_contents) const {
   return main_window_ && web_contents == main_window_->web_contents();
 }
diff --git a/content/shell/browser/layout_test/blink_test_controller.h b/content/shell/browser/layout_test/blink_test_controller.h
index 56f898b..3b15a60 100644
--- a/content/shell/browser/layout_test/blink_test_controller.h
+++ b/content/shell/browser/layout_test/blink_test_controller.h
@@ -250,11 +250,20 @@
   void OnCaptureDumpCompleted(mojom::LayoutTestDumpPtr dump);
   void OnPixelDumpCaptured(const SkBitmap& snapshot);
   void ReportResults();
+  void EnqueueSurfaceCopyRequest();
 
-  void CompositeAllFrames();
-  Node* BuildFrameTree(const std::vector<RenderFrameHost*>& frames,
-                       std::vector<Node>* storage) const;
-  void CompositeDepthFirst(Node* node);
+  // CompositeAllFramesThen() first builds a frame tree based on
+  // frame->GetParent(). Then, it builds a queue of frames in depth-first order,
+  // so that compositing happens from the leaves up. Finally,
+  // CompositeNodeQueueThen() is used to composite one frame at a time,
+  // asynchronously, continuing on to the next frame once each composite
+  // finishes. Once all nodes have been composited, the final callback is run.
+  // Each call to CompositeWithRaster() is an asynchronous Mojo call, to avoid
+  // reentrancy problems.
+  void CompositeAllFramesThen(base::OnceCallback<void()> callback);
+  Node* BuildFrameTree(const std::vector<RenderFrameHost*>& frames);
+  void CompositeNodeQueueThen(base::OnceCallback<void()> callback);
+  void BuildDepthFirstQueue(Node* node);
 
   std::unique_ptr<BlinkTestResultPrinter> printer_;
 
@@ -329,6 +338,9 @@
   bool waiting_for_pixel_results_ = false;
   bool waiting_for_main_frame_dump_ = false;
 
+  std::vector<Node> composite_all_frames_node_storage_;
+  std::queue<Node*> composite_all_frames_node_queue_;
+
   // Map from one frame to one mojo pipe.
   std::map<GlobalFrameRoutingId, mojom::LayoutTestControlAssociatedPtr>
       layout_test_control_map_;
diff --git a/content/shell/common/layout_test.mojom b/content/shell/common/layout_test.mojom
index ae4e13d4..be9a11b6 100644
--- a/content/shell/common/layout_test.mojom
+++ b/content/shell/common/layout_test.mojom
@@ -51,7 +51,7 @@
 interface LayoutTestControl {
   CaptureDump() => (LayoutTestDump result);
 
-  [Sync] CompositeWithRaster() => ();
+  CompositeWithRaster() => ();
 
   // Dumps the frame's contents into a string.
   DumpFrameLayout() => (string frame_layout_dump);
diff --git a/device/BUILD.gn b/device/BUILD.gn
index f18e8a4..3bcd647 100644
--- a/device/BUILD.gn
+++ b/device/BUILD.gn
@@ -75,7 +75,7 @@
     "fido/ble/fido_ble_frames_unittest.cc",
     "fido/ble/fido_ble_pairing_delegate_unittest.cc",
     "fido/ble/fido_ble_transaction_unittest.cc",
-    "fido/ble_adapter_power_manager_unittest.cc",
+    "fido/ble_adapter_manager_unittest.cc",
     "fido/cable/fido_cable_device_unittest.cc",
     "fido/cable/fido_cable_discovery_unittest.cc",
     "fido/cable/fido_cable_handshake_handler_unittest.cc",
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc
index 54ec734..efac70e 100644
--- a/device/bluetooth/bluetooth_adapter.cc
+++ b/device/bluetooth/bluetooth_adapter.cc
@@ -171,7 +171,7 @@
   RemovePairingDelegate(pairing_delegate);
 
   // Find the first point with a lower priority, or the end of the list.
-  std::list<PairingDelegatePair>::iterator iter = pairing_delegates_.begin();
+  auto iter = pairing_delegates_.begin();
   while (iter != pairing_delegates_.end() && iter->second >= priority)
     ++iter;
 
@@ -180,8 +180,8 @@
 
 void BluetoothAdapter::RemovePairingDelegate(
     BluetoothDevice::PairingDelegate* pairing_delegate) {
-  for (std::list<PairingDelegatePair>::iterator iter =
-       pairing_delegates_.begin(); iter != pairing_delegates_.end(); ++iter) {
+  for (auto iter = pairing_delegates_.begin(); iter != pairing_delegates_.end();
+       ++iter) {
     if (iter->first == pairing_delegate) {
       RemovePairingDelegateInternal(pairing_delegate);
       pairing_delegates_.erase(iter);
@@ -369,9 +369,7 @@
   // |discovery_sessions_|. To avoid invalidating the iterator, make a copy
   // here.
   std::set<BluetoothDiscoverySession*> temp(discovery_sessions_);
-  for (std::set<BluetoothDiscoverySession*>::iterator
-          iter = temp.begin();
-       iter != temp.end(); ++iter) {
+  for (auto iter = temp.begin(); iter != temp.end(); ++iter) {
     (*iter)->MarkAsInactive();
   }
 }
diff --git a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
index e84ab7f..c81a498 100644
--- a/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
+++ b/device/bluetooth/bluetooth_remote_gatt_characteristic.cc
@@ -289,8 +289,7 @@
     NotifySessionCommand::Type previous_command_type,
     NotifySessionCommand::Result previous_command_result,
     BluetoothRemoteGattService::GattErrorCode previous_command_error_code) {
-  std::set<BluetoothGattNotifySession*>::iterator session_iterator =
-      notify_sessions_.find(session);
+  auto session_iterator = notify_sessions_.find(session);
 
   // If the session does not even belong to this characteristic, we return an
   // error right away.
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
index a5c5c49..3a67b33 100644
--- a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -1010,8 +1010,7 @@
           ->GetBluetoothDeviceClient()
           ->GetDevicesForAdapter(object_path_);
 
-  for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
-       iter != device_paths.end(); ++iter) {
+  for (auto iter = device_paths.begin(); iter != device_paths.end(); ++iter) {
     DeviceAdded(*iter);
   }
 }
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc
index 1bbc2b7..1ea1ce2d 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_characteristic_bluez.cc
@@ -32,8 +32,7 @@
 // Stream operator for logging vector<uint8_t>.
 std::ostream& operator<<(std::ostream& out, const std::vector<uint8_t> bytes) {
   out << "[";
-  for (std::vector<uint8_t>::const_iterator iter = bytes.begin();
-       iter != bytes.end(); ++iter) {
+  for (auto iter = bytes.begin(); iter != bytes.end(); ++iter) {
     out << base::StringPrintf("%02X", *iter);
   }
   return out << "]";
@@ -60,8 +59,7 @@
       bluez::BluezDBusManager::Get()
           ->GetBluetoothGattDescriptorClient()
           ->GetDescriptors();
-  for (std::vector<dbus::ObjectPath>::const_iterator iter = gatt_descs.begin();
-       iter != gatt_descs.end(); ++iter)
+  for (auto iter = gatt_descs.begin(); iter != gatt_descs.end(); ++iter)
     GattDescriptorAdded(*iter);
 }
 
@@ -91,8 +89,7 @@
 
   Properties props = PROPERTY_NONE;
   const std::vector<std::string>& flags = properties->flags.value();
-  for (std::vector<std::string>::const_iterator iter = flags.begin();
-       iter != flags.end(); ++iter) {
+  for (auto iter = flags.begin(); iter != flags.end(); ++iter) {
     if (*iter == bluetooth_gatt_characteristic::kFlagBroadcast)
       props |= PROPERTY_BROADCAST;
     if (*iter == bluetooth_gatt_characteristic::kFlagRead)
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.cc b/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.cc
index e46f221a..7efbbd5 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_descriptor_bluez.cc
@@ -27,8 +27,7 @@
 // Stream operator for logging vector<uint8_t>.
 std::ostream& operator<<(std::ostream& out, const std::vector<uint8_t> bytes) {
   out << "[";
-  for (std::vector<uint8_t>::const_iterator iter = bytes.begin();
-       iter != bytes.end(); ++iter) {
+  for (auto iter = bytes.begin(); iter != bytes.end(); ++iter) {
     out << base::StringPrintf("%02X", *iter);
   }
   return out << "]";
diff --git a/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.cc b/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.cc
index fbc94a2e..ea34248 100644
--- a/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.cc
+++ b/device/bluetooth/bluez/bluetooth_remote_gatt_service_bluez.cc
@@ -40,8 +40,7 @@
       bluez::BluezDBusManager::Get()
           ->GetBluetoothGattCharacteristicClient()
           ->GetCharacteristics();
-  for (std::vector<dbus::ObjectPath>::const_iterator iter = gatt_chars.begin();
-       iter != gatt_chars.end(); ++iter)
+  for (auto iter = gatt_chars.begin(); iter != gatt_chars.end(); ++iter)
     GattCharacteristicAdded(*iter);
 }
 
@@ -181,7 +180,7 @@
 
 void BluetoothRemoteGattServiceBlueZ::GattCharacteristicRemoved(
     const dbus::ObjectPath& object_path) {
-  CharacteristicMap::iterator iter = characteristics_.find(object_path.value());
+  auto iter = characteristics_.find(object_path.value());
   if (iter == characteristics_.end()) {
     VLOG(2) << "Unknown GATT characteristic removed: " << object_path.value();
     return;
diff --git a/device/bluetooth/dbus/bluetooth_device_client.cc b/device/bluetooth/dbus/bluetooth_device_client.cc
index 5167d69..11ceed8b 100644
--- a/device/bluetooth/dbus/bluetooth_device_client.cc
+++ b/device/bluetooth/dbus/bluetooth_device_client.cc
@@ -255,8 +255,7 @@
     std::vector<dbus::ObjectPath> object_paths, device_paths;
     device_paths = object_manager_->GetObjectsWithInterface(
         bluetooth_device::kBluetoothDeviceInterface);
-    for (std::vector<dbus::ObjectPath>::iterator iter = device_paths.begin();
-         iter != device_paths.end(); ++iter) {
+    for (auto iter = device_paths.begin(); iter != device_paths.end(); ++iter) {
       Properties* properties = GetProperties(*iter);
       if (properties->adapter.value() == adapter_path)
         object_paths.push_back(*iter);
diff --git a/device/bluetooth/dbus/fake_bluetooth_device_client.cc b/device/bluetooth/dbus/fake_bluetooth_device_client.cc
index b8fd119..c5533ddc 100644
--- a/device/bluetooth/dbus/fake_bluetooth_device_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_device_client.cc
@@ -1109,7 +1109,7 @@
 void FakeBluetoothDeviceClient::RemoveDevice(
     const dbus::ObjectPath& adapter_path,
     const dbus::ObjectPath& device_path) {
-  std::vector<dbus::ObjectPath>::iterator listiter =
+  auto listiter =
       std::find(device_list_.begin(), device_list_.end(), device_path);
   if (listiter == device_list_.end())
     return;
diff --git a/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.cc b/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.cc
index 9745715..a3b2acb 100644
--- a/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.cc
@@ -59,8 +59,7 @@
     : weak_ptr_factory_(this) {}
 
 FakeBluetoothGattDescriptorClient::~FakeBluetoothGattDescriptorClient() {
-  for (PropertiesMap::iterator iter = properties_.begin();
-       iter != properties_.end(); iter++)
+  for (auto iter = properties_.begin(); iter != properties_.end(); iter++)
     delete iter->second;
 }
 
@@ -99,7 +98,7 @@
     const dbus::ObjectPath& object_path,
     const ValueCallback& callback,
     const ErrorCallback& error_callback) {
-  PropertiesMap::iterator iter = properties_.find(object_path);
+  auto iter = properties_.find(object_path);
   if (iter == properties_.end()) {
     error_callback.Run(kUnknownDescriptorError, "");
     return;
@@ -180,7 +179,7 @@
 
 void FakeBluetoothGattDescriptorClient::HideDescriptor(
     const dbus::ObjectPath& descriptor_path) {
-  PropertiesMap::iterator iter = properties_.find(descriptor_path);
+  auto iter = properties_.find(descriptor_path);
   if (iter == properties_.end()) {
     VLOG(1) << "Descriptor not exposed: " << descriptor_path.value();
     return;
diff --git a/device/bluetooth/dbus/fake_bluetooth_gatt_manager_client.cc b/device/bluetooth/dbus/fake_bluetooth_gatt_manager_client.cc
index b2fdd2c..23b7cf2 100644
--- a/device/bluetooth/dbus/fake_bluetooth_gatt_manager_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_gatt_manager_client.cc
@@ -145,8 +145,7 @@
 
 void FakeBluetoothGattManagerClient::UnregisterApplicationServiceProvider(
     FakeBluetoothGattApplicationServiceProvider* provider) {
-  ApplicationMap::iterator iter =
-      application_map_.find(provider->object_path());
+  auto iter = application_map_.find(provider->object_path());
   if (iter != application_map_.end() && iter->second.first == provider)
     application_map_.erase(iter);
 }
@@ -154,14 +153,14 @@
 FakeBluetoothGattManagerClient::ApplicationProvider*
 FakeBluetoothGattManagerClient::GetApplicationServiceProvider(
     const dbus::ObjectPath& object_path) {
-  ApplicationMap::iterator iter = application_map_.find(object_path);
+  auto iter = application_map_.find(object_path);
   return (iter != application_map_.end()) ? &iter->second : nullptr;
 }
 
 void FakeBluetoothGattManagerClient::RegisterServiceServiceProvider(
     FakeBluetoothGattServiceServiceProvider* provider) {
   // Ignore, if a service provider is already registered for the object path.
-  ServiceMap::iterator iter = service_map_.find(provider->object_path());
+  auto iter = service_map_.find(provider->object_path());
   if (iter != service_map_.end()) {
     VLOG(1) << "GATT service service provider already registered for "
             << "object path: " << provider->object_path().value();
@@ -173,8 +172,7 @@
 void FakeBluetoothGattManagerClient::RegisterCharacteristicServiceProvider(
     FakeBluetoothGattCharacteristicServiceProvider* provider) {
   // Ignore, if a service provider is already registered for the object path.
-  CharacteristicMap::iterator iter =
-      characteristic_map_.find(provider->object_path());
+  auto iter = characteristic_map_.find(provider->object_path());
   if (iter != characteristic_map_.end()) {
     VLOG(1) << "GATT characteristic service provider already registered for "
             << "object path: " << provider->object_path().value();
@@ -186,7 +184,7 @@
 void FakeBluetoothGattManagerClient::RegisterDescriptorServiceProvider(
     FakeBluetoothGattDescriptorServiceProvider* provider) {
   // Ignore, if a service provider is already registered for the object path.
-  DescriptorMap::iterator iter = descriptor_map_.find(provider->object_path());
+  auto iter = descriptor_map_.find(provider->object_path());
   if (iter != descriptor_map_.end()) {
     VLOG(1) << "GATT descriptor service provider already registered for "
             << "object path: " << provider->object_path().value();
@@ -197,7 +195,7 @@
 
 void FakeBluetoothGattManagerClient::UnregisterServiceServiceProvider(
     FakeBluetoothGattServiceServiceProvider* provider) {
-  ServiceMap::iterator iter = service_map_.find(provider->object_path());
+  auto iter = service_map_.find(provider->object_path());
   if (iter != service_map_.end() && iter->second == provider)
     service_map_.erase(iter);
 }
@@ -215,7 +213,7 @@
 FakeBluetoothGattServiceServiceProvider*
 FakeBluetoothGattManagerClient::GetServiceServiceProvider(
     const dbus::ObjectPath& object_path) const {
-  ServiceMap::const_iterator iter = service_map_.find(object_path);
+  auto iter = service_map_.find(object_path);
   if (iter == service_map_.end())
     return NULL;
   return iter->second;
@@ -224,8 +222,7 @@
 FakeBluetoothGattCharacteristicServiceProvider*
 FakeBluetoothGattManagerClient::GetCharacteristicServiceProvider(
     const dbus::ObjectPath& object_path) const {
-  CharacteristicMap::const_iterator iter =
-      characteristic_map_.find(object_path);
+  auto iter = characteristic_map_.find(object_path);
   if (iter == characteristic_map_.end())
     return NULL;
   return iter->second;
@@ -234,7 +231,7 @@
 FakeBluetoothGattDescriptorServiceProvider*
 FakeBluetoothGattManagerClient::GetDescriptorServiceProvider(
     const dbus::ObjectPath& object_path) const {
-  DescriptorMap::const_iterator iter = descriptor_map_.find(object_path);
+  auto iter = descriptor_map_.find(object_path);
   if (iter == descriptor_map_.end())
     return NULL;
   return iter->second;
diff --git a/device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.cc b/device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.cc
index 24623377..fc9dd4b3 100644
--- a/device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_le_advertising_manager_client.cc
@@ -52,8 +52,7 @@
     return;
   }
 
-  ServiceProviderMap::iterator iter =
-      service_provider_map_.find(advertisement_object_path);
+  auto iter = service_provider_map_.find(advertisement_object_path);
   if (iter == service_provider_map_.end()) {
     error_callback.Run(bluetooth_advertising_manager::kErrorInvalidArguments,
                        "Advertisement object not registered");
@@ -128,8 +127,7 @@
 void FakeBluetoothLEAdvertisingManagerClient::
     UnregisterAdvertisementServiceProvider(
         FakeBluetoothLEAdvertisementServiceProvider* service_provider) {
-  ServiceProviderMap::iterator iter =
-      service_provider_map_.find(service_provider->object_path_);
+  auto iter = service_provider_map_.find(service_provider->object_path_);
   if (iter != service_provider_map_.end() && iter->second == service_provider)
     service_provider_map_.erase(iter);
 }
diff --git a/device/bluetooth/dbus/fake_bluetooth_profile_manager_client.cc b/device/bluetooth/dbus/fake_bluetooth_profile_manager_client.cc
index 771a8ec1..181d903 100644
--- a/device/bluetooth/dbus/fake_bluetooth_profile_manager_client.cc
+++ b/device/bluetooth/dbus/fake_bluetooth_profile_manager_client.cc
@@ -52,12 +52,12 @@
 
   // TODO(jamuraa): check options for channel & psm
 
-  ServiceProviderMap::iterator iter = service_provider_map_.find(profile_path);
+  auto iter = service_provider_map_.find(profile_path);
   if (iter == service_provider_map_.end()) {
     error_callback.Run(bluetooth_profile_manager::kErrorInvalidArguments,
                        "No profile created");
   } else {
-    ProfileMap::iterator piter = profile_map_.find(uuid);
+    auto piter = profile_map_.find(uuid);
     if (piter != profile_map_.end()) {
       error_callback.Run(bluetooth_profile_manager::kErrorAlreadyExists,
                          "Profile already registered");
@@ -74,13 +74,13 @@
     const ErrorCallback& error_callback) {
   VLOG(1) << "UnregisterProfile: " << profile_path.value();
 
-  ServiceProviderMap::iterator iter = service_provider_map_.find(profile_path);
+  auto iter = service_provider_map_.find(profile_path);
   if (iter == service_provider_map_.end()) {
     error_callback.Run(bluetooth_profile_manager::kErrorInvalidArguments,
                        "Profile not registered");
   } else {
-    for (ProfileMap::iterator piter = profile_map_.begin();
-         piter != profile_map_.end(); ++piter) {
+    for (auto piter = profile_map_.begin(); piter != profile_map_.end();
+         ++piter) {
       if (piter->second == profile_path) {
         profile_map_.erase(piter);
         break;
@@ -98,8 +98,7 @@
 
 void FakeBluetoothProfileManagerClient::UnregisterProfileServiceProvider(
     FakeBluetoothProfileServiceProvider* service_provider) {
-  ServiceProviderMap::iterator iter =
-      service_provider_map_.find(service_provider->object_path_);
+  auto iter = service_provider_map_.find(service_provider->object_path_);
   if (iter != service_provider_map_.end() && iter->second == service_provider)
     service_provider_map_.erase(iter);
 }
@@ -107,7 +106,7 @@
 FakeBluetoothProfileServiceProvider*
 FakeBluetoothProfileManagerClient::GetProfileServiceProvider(
     const std::string& uuid) {
-  ProfileMap::iterator iter = profile_map_.find(uuid);
+  auto iter = profile_map_.find(uuid);
   if (iter == profile_map_.end())
     return nullptr;
   return service_provider_map_[iter->second];
diff --git a/device/fido/BUILD.gn b/device/fido/BUILD.gn
index c7c12b4..1d7bed1 100644
--- a/device/fido/BUILD.gn
+++ b/device/fido/BUILD.gn
@@ -43,8 +43,8 @@
     "ble/fido_ble_transaction.h",
     "ble/fido_ble_uuids.cc",
     "ble/fido_ble_uuids.h",
-    "ble_adapter_power_manager.cc",
-    "ble_adapter_power_manager.h",
+    "ble_adapter_manager.cc",
+    "ble_adapter_manager.h",
     "cable/cable_discovery_data.h",
     "cable/fido_cable_device.cc",
     "cable/fido_cable_device.h",
@@ -98,6 +98,7 @@
     "opaque_attestation_statement.h",
     "opaque_public_key.cc",
     "opaque_public_key.h",
+    "platform_credential_store.h",
     "public_key.cc",
     "public_key.h",
     "public_key_credential_descriptor.cc",
@@ -165,10 +166,11 @@
     sources += [
       "mac/authenticator.h",
       "mac/authenticator.mm",
-      "mac/browsing_data_deletion.h",
-      "mac/browsing_data_deletion.mm",
+      "mac/authenticator_config.h",
       "mac/credential_metadata.cc",
       "mac/credential_metadata.h",
+      "mac/credential_store.h",
+      "mac/credential_store.mm",
       "mac/get_assertion_operation.h",
       "mac/get_assertion_operation.mm",
       "mac/keychain.h",
diff --git a/device/fido/ble/fido_ble_connection.cc b/device/fido/ble/fido_ble_connection.cc
index cb56324..32291b6 100644
--- a/device/fido/ble/fido_ble_connection.cc
+++ b/device/fido/ble/fido_ble_connection.cc
@@ -471,6 +471,13 @@
   std::move(pending_connection_callback_).Run(false);
 }
 
+void FidoBleConnection::DeviceAddressChanged(BluetoothAdapter* adapter,
+                                             BluetoothDevice* device,
+                                             const std::string& old_address) {
+  if (address_ == old_address)
+    address_ = device->GetAddress();
+}
+
 void FidoBleConnection::GattCharacteristicValueChanged(
     BluetoothAdapter* adapter,
     BluetoothRemoteGattCharacteristic* characteristic,
diff --git a/device/fido/ble/fido_ble_connection.h b/device/fido/ble/fido_ble_connection.h
index 34174629..ecc59942 100644
--- a/device/fido/ble/fido_ble_connection.h
+++ b/device/fido/ble/fido_ble_connection.h
@@ -77,6 +77,9 @@
 
  private:
   // BluetoothAdapter::Observer:
+  void DeviceAddressChanged(BluetoothAdapter* adapter,
+                            BluetoothDevice* device,
+                            const std::string& old_address) override;
   void GattCharacteristicValueChanged(
       BluetoothAdapter* adapter,
       BluetoothRemoteGattCharacteristic* characteristic,
diff --git a/device/fido/ble/fido_ble_connection_unittest.cc b/device/fido/ble/fido_ble_connection_unittest.cc
index 865a92f..507297fb 100644
--- a/device/fido/ble/fido_ble_connection_unittest.cc
+++ b/device/fido/ble/fido_ble_connection_unittest.cc
@@ -209,6 +209,15 @@
     adapter_->NotifyGattServicesDiscovered(fido_device_);
   }
 
+  void ChangeDeviceAddressAndNotifyObservers(std::string new_address) {
+    auto old_address = fido_device_->GetAddress();
+    EXPECT_CALL(*fido_device_, GetAddress)
+        .WillRepeatedly(::testing::Return(new_address));
+    for (auto& observer : adapter_->GetObservers())
+      observer.DeviceAddressChanged(adapter_.get(), fido_device_,
+                                    std::move(old_address));
+  }
+
   void SetNextReadControlPointLengthReponse(bool success,
                                             const std::vector<uint8_t>& value) {
     EXPECT_CALL(*fido_control_point_length_, ReadRemoteCharacteristic(_, _))
@@ -735,4 +744,15 @@
   EXPECT_FALSE(write_callback.value());
 }
 
+TEST_F(FidoBleConnectionTest, ConnectionAddressChangeWhenDeviceAddressChanges) {
+  const std::string device_address = BluetoothTest::kTestDeviceAddress1;
+  static constexpr char kTestDeviceAddress2[] = "test_device_address_2";
+
+  AddFidoDevice(device_address);
+  SetupConnectingFidoDevice(device_address);
+  FidoBleConnection connection(adapter(), device_address, base::DoNothing());
+  ChangeDeviceAddressAndNotifyObservers(kTestDeviceAddress2);
+  EXPECT_EQ(kTestDeviceAddress2, connection.address());
+}
+
 }  // namespace device
diff --git a/device/fido/ble/fido_ble_discovery.cc b/device/fido/ble/fido_ble_discovery.cc
index 6527069..b683caf7 100644
--- a/device/fido/ble/fido_ble_discovery.cc
+++ b/device/fido/ble/fido_ble_discovery.cc
@@ -93,6 +93,26 @@
     OnSetPowered();
 }
 
+void FidoBleDiscovery::DeviceAddressChanged(BluetoothAdapter* adapter,
+                                            BluetoothDevice* device,
+                                            const std::string& old_address) {
+  auto previous_device_id = FidoBleDevice::GetId(old_address);
+  auto new_device_id = FidoBleDevice::GetId(device->GetAddress());
+  auto it = devices_.find(previous_device_id);
+  if (it == devices_.end())
+    return;
+
+  VLOG(2) << "Discovered FIDO BLE device address change from old address : "
+          << old_address << " to new address : " << device->GetAddress();
+  devices_.emplace(new_device_id, std::move(it->second));
+  devices_.erase(it);
+
+  if (observer()) {
+    observer()->DeviceIdChanged(this, previous_device_id,
+                                std::move(new_device_id));
+  }
+}
+
 bool FidoBleDiscovery::CheckForExcludedDeviceAndCacheAddress(
     const BluetoothDevice* device) {
   std::string device_address = device->GetAddress();
diff --git a/device/fido/ble/fido_ble_discovery.h b/device/fido/ble/fido_ble_discovery.h
index cc804cf..0b03b86 100644
--- a/device/fido/ble/fido_ble_discovery.h
+++ b/device/fido/ble/fido_ble_discovery.h
@@ -38,6 +38,9 @@
   void DeviceRemoved(BluetoothAdapter* adapter,
                      BluetoothDevice* device) override;
   void AdapterPoweredChanged(BluetoothAdapter* adapter, bool powered) override;
+  void DeviceAddressChanged(BluetoothAdapter* adapter,
+                            BluetoothDevice* device,
+                            const std::string& old_address) override;
 
   // Returns true if |device| is a Cable device. If so, add address of |device|
   // to |blacklisted_cable_device_addresses_|.
diff --git a/device/fido/ble/fido_ble_discovery_unittest.cc b/device/fido/ble/fido_ble_discovery_unittest.cc
index 74efa866..5b34cefd 100644
--- a/device/fido/ble/fido_ble_discovery_unittest.cc
+++ b/device/fido/ble/fido_ble_discovery_unittest.cc
@@ -5,6 +5,7 @@
 #include "device/fido/ble/fido_ble_discovery.h"
 
 #include <string>
+#include <vector>
 
 #include "base/bind.h"
 #include "base/run_loop.h"
@@ -12,7 +13,9 @@
 #include "device/bluetooth/bluetooth_adapter_factory.h"
 #include "device/bluetooth/test/bluetooth_test.h"
 #include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "device/bluetooth/test/mock_bluetooth_device.h"
 #include "device/fido/ble/fido_ble_device.h"
+#include "device/fido/ble/fido_ble_uuids.h"
 #include "device/fido/mock_fido_discovery_observer.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -232,4 +235,52 @@
   SimulateLowEnergyDevice(7);
 }
 
+TEST_F(BluetoothTest, DiscoveryDoesNotAddDuplicateDeviceOnAddressChanged) {
+  using TestMockDevice = ::testing::NiceMock<MockBluetoothDevice>;
+  static constexpr char kDeviceName[] = "device_name";
+  static constexpr char kDeviceAddress[] = "device_address";
+  static constexpr char kAuthenticatorId[] = "ble:device_address";
+  static constexpr char kDeviceChangedAddress[] = "device_changed_address";
+  static constexpr char kAuthenticatorChangedId[] =
+      "ble:device_changed_address";
+
+  MockFidoDiscoveryObserver observer;
+  FidoBleDiscovery discovery;
+  discovery.set_observer(&observer);
+
+  auto mock_adapter =
+      base::MakeRefCounted<::testing::NiceMock<MockBluetoothAdapter>>();
+  EXPECT_CALL(*mock_adapter, IsPresent()).WillOnce(::testing::Return(true));
+
+  auto mock_device = std::make_unique<TestMockDevice>(
+      mock_adapter.get(), 0 /* bluetooth_class */, kDeviceName, kDeviceAddress,
+      false /* paired */, false /* connected */);
+
+  EXPECT_CALL(*mock_device.get(), GetUUIDs)
+      .WillRepeatedly(::testing::Return(
+          std::vector<BluetoothUUID>{BluetoothUUID(kFidoServiceUUID)}));
+
+  BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter.get());
+  EXPECT_CALL(observer, DeviceIdChanged(&discovery, kAuthenticatorId,
+                                        kAuthenticatorChangedId));
+  discovery.Start();
+
+  EXPECT_CALL(*mock_device.get(), GetAddress)
+      .WillRepeatedly(::testing::Return(kDeviceAddress));
+  mock_adapter->NotifyDeviceChanged(mock_device.get());
+  ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(mock_device.get()));
+
+  EXPECT_CALL(*mock_device.get(), GetAddress)
+      .WillRepeatedly(::testing::Return(kDeviceChangedAddress));
+  for (auto& observer : mock_adapter->GetObservers()) {
+    observer.DeviceAddressChanged(mock_adapter.get(), mock_device.get(),
+                                  kDeviceAddress);
+  }
+
+  mock_adapter->NotifyDeviceChanged(mock_device.get());
+
+  EXPECT_EQ(1u, discovery.GetDevices().size());
+  EXPECT_TRUE(discovery.GetDevice(kAuthenticatorChangedId));
+}
+
 }  // namespace device
diff --git a/device/fido/ble/fido_ble_pairing_delegate.cc b/device/fido/ble/fido_ble_pairing_delegate.cc
index 942f700..4b2ec0b 100644
--- a/device/fido/ble/fido_ble_pairing_delegate.cc
+++ b/device/fido/ble/fido_ble_pairing_delegate.cc
@@ -76,4 +76,16 @@
                                                  std::move(pin_code));
 }
 
+void FidoBlePairingDelegate::ChangeStoredDeviceAddress(
+    const std::string& old_address,
+    std::string new_address) {
+  auto it = bluetooth_device_pincode_map_.find(old_address);
+  if (it != bluetooth_device_pincode_map_.end()) {
+    std::string pincode = std::move(it->second);
+    bluetooth_device_pincode_map_.erase(it);
+    bluetooth_device_pincode_map_.insert_or_assign(std::move(new_address),
+                                                   std::move(pincode));
+  }
+}
+
 }  // namespace device
diff --git a/device/fido/ble/fido_ble_pairing_delegate.h b/device/fido/ble/fido_ble_pairing_delegate.h
index 3208b5df..a31f4e5 100644
--- a/device/fido/ble/fido_ble_pairing_delegate.h
+++ b/device/fido/ble/fido_ble_pairing_delegate.h
@@ -40,8 +40,12 @@
 
   void StoreBlePinCodeForDevice(std::string device_address,
                                 std::string pin_code);
+  void ChangeStoredDeviceAddress(const std::string& old_address,
+                                 std::string new_address);
 
  private:
+  friend class FidoBlePairingDelegateTest;
+
   base::flat_map<std::string, std::string> bluetooth_device_pincode_map_;
 
   DISALLOW_COPY_AND_ASSIGN(FidoBlePairingDelegate);
diff --git a/device/fido/ble/fido_ble_pairing_delegate_unittest.cc b/device/fido/ble/fido_ble_pairing_delegate_unittest.cc
index c6c9cd8f..465893b 100644
--- a/device/fido/ble/fido_ble_pairing_delegate_unittest.cc
+++ b/device/fido/ble/fido_ble_pairing_delegate_unittest.cc
@@ -20,6 +20,8 @@
 constexpr uint32_t kTestPassKey = 1234;
 constexpr char kTestBluetoothDeviceName[] = "device_name";
 
+}  // namespace
+
 class FidoBlePairingDelegateTest : public ::testing::Test {
  public:
   FidoBlePairingDelegate* pairing_delegate() { return pairing_delegate_.get(); }
@@ -27,6 +29,11 @@
     return mock_bluetooth_device_.get();
   }
 
+  const base::flat_map<std::string, std::string>&
+  pairing_delegate_pincode_map() {
+    return pairing_delegate_->bluetooth_device_pincode_map_;
+  }
+
  private:
   std::unique_ptr<FidoBlePairingDelegate> pairing_delegate_ =
       std::make_unique<FidoBlePairingDelegate>();
@@ -39,8 +46,6 @@
                                             false /* connected */);
 };
 
-}  // namespace
-
 TEST_F(FidoBlePairingDelegateTest, PairingWithPin) {
   pairing_delegate()->StoreBlePinCodeForDevice(kTestFidoBleDeviceId,
                                                kTestPinCode);
@@ -89,4 +94,22 @@
   pairing_delegate()->ConfirmPasskey(mock_bluetooth_device(), kTestPassKey);
 }
 
+TEST_F(FidoBlePairingDelegateTest, ChangeStoredDeviceAddress) {
+  static constexpr char kTestNewBleDeviceAddress[] =
+      "ble:test_changed_device_address";
+  pairing_delegate()->StoreBlePinCodeForDevice(kTestFidoBleDeviceId,
+                                               kTestPinCode);
+  EXPECT_TRUE(
+      base::ContainsKey(pairing_delegate_pincode_map(), kTestFidoBleDeviceId));
+  EXPECT_FALSE(base::ContainsKey(pairing_delegate_pincode_map(),
+                                 kTestNewBleDeviceAddress));
+
+  pairing_delegate()->ChangeStoredDeviceAddress(kTestFidoBleDeviceId,
+                                                kTestNewBleDeviceAddress);
+  EXPECT_FALSE(
+      base::ContainsKey(pairing_delegate_pincode_map(), kTestFidoBleDeviceId));
+  EXPECT_TRUE(base::ContainsKey(pairing_delegate_pincode_map(),
+                                kTestNewBleDeviceAddress));
+}
+
 }  // namespace device
diff --git a/device/fido/ble_adapter_power_manager.cc b/device/fido/ble_adapter_manager.cc
similarity index 65%
rename from device/fido/ble_adapter_power_manager.cc
rename to device/fido/ble_adapter_manager.cc
index 7c7a8ec3..e9b3a88 100644
--- a/device/fido/ble_adapter_power_manager.cc
+++ b/device/fido/ble_adapter_manager.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/ble_adapter_power_manager.h"
+#include "device/fido/ble_adapter_manager.h"
 
 #include <utility>
 
@@ -11,14 +11,13 @@
 
 namespace device {
 
-BleAdapterPowerManager::BleAdapterPowerManager(
-    FidoRequestHandlerBase* request_handler)
+BleAdapterManager::BleAdapterManager(FidoRequestHandlerBase* request_handler)
     : request_handler_(request_handler), weak_factory_(this) {
   BluetoothAdapterFactory::Get().GetAdapter(base::BindRepeating(
-      &BleAdapterPowerManager::Start, weak_factory_.GetWeakPtr()));
+      &BleAdapterManager::Start, weak_factory_.GetWeakPtr()));
 }
 
-BleAdapterPowerManager::~BleAdapterPowerManager() {
+BleAdapterManager::~BleAdapterManager() {
   if (adapter_powered_on_programmatically_)
     SetAdapterPower(false /* set_power_on */);
 
@@ -26,19 +25,19 @@
     adapter_->RemoveObserver(this);
 }
 
-void BleAdapterPowerManager::SetAdapterPower(bool set_power_on) {
+void BleAdapterManager::SetAdapterPower(bool set_power_on) {
   if (set_power_on)
     adapter_powered_on_programmatically_ = true;
 
   adapter_->SetPowered(set_power_on, base::DoNothing(), base::DoNothing());
 }
 
-void BleAdapterPowerManager::AdapterPoweredChanged(BluetoothAdapter* adapter,
-                                                   bool powered) {
+void BleAdapterManager::AdapterPoweredChanged(BluetoothAdapter* adapter,
+                                              bool powered) {
   request_handler_->OnBluetoothAdapterPowerChanged(powered);
 }
 
-void BleAdapterPowerManager::Start(scoped_refptr<BluetoothAdapter> adapter) {
+void BleAdapterManager::Start(scoped_refptr<BluetoothAdapter> adapter) {
   DCHECK(!adapter_);
   adapter_ = std::move(adapter);
   DCHECK(adapter_);
diff --git a/device/fido/ble_adapter_power_manager.h b/device/fido/ble_adapter_manager.h
similarity index 71%
rename from device/fido/ble_adapter_power_manager.h
rename to device/fido/ble_adapter_manager.h
index 194e0def..0990b0d 100644
--- a/device/fido/ble_adapter_power_manager.h
+++ b/device/fido/ble_adapter_manager.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef DEVICE_FIDO_BLE_ADAPTER_POWER_MANAGER_H_
-#define DEVICE_FIDO_BLE_ADAPTER_POWER_MANAGER_H_
+#ifndef DEVICE_FIDO_BLE_ADAPTER_MANAGER_H_
+#define DEVICE_FIDO_BLE_ADAPTER_MANAGER_H_
 
 #include "base/component_export.h"
 #include "base/macros.h"
@@ -14,7 +14,7 @@
 
 namespace device {
 
-class COMPONENT_EXPORT(DEVICE_FIDO) BleAdapterPowerManager
+class COMPONENT_EXPORT(DEVICE_FIDO) BleAdapterManager
     : public BluetoothAdapter::Observer {
  public:
   // Handles notifying |request_handler| when BluetoothAdapter is powered on and
@@ -22,13 +22,13 @@
   // programmatically, and if BluetoothAdapter was powered on programmatically,
   // powers off BluetoothAdapter when |this| goes out of scope.
   // |request_handler| must outlive |this|.
-  BleAdapterPowerManager(FidoRequestHandlerBase* request_handler);
-  ~BleAdapterPowerManager() override;
+  BleAdapterManager(FidoRequestHandlerBase* request_handler);
+  ~BleAdapterManager() override;
 
   void SetAdapterPower(bool set_power_on);
 
  private:
-  friend class FidoBleAdapterPowerManagerTest;
+  friend class FidoBleAdapterManagerTest;
 
   // BluetoothAdapter::Observer:
   void AdapterPoweredChanged(BluetoothAdapter* adapter, bool powered) override;
@@ -39,11 +39,11 @@
   scoped_refptr<BluetoothAdapter> adapter_;
   bool adapter_powered_on_programmatically_ = false;
 
-  base::WeakPtrFactory<BleAdapterPowerManager> weak_factory_;
+  base::WeakPtrFactory<BleAdapterManager> weak_factory_;
 
-  DISALLOW_COPY_AND_ASSIGN(BleAdapterPowerManager);
+  DISALLOW_COPY_AND_ASSIGN(BleAdapterManager);
 };
 
 }  // namespace device
 
-#endif  // DEVICE_FIDO_BLE_ADAPTER_POWER_MANAGER_H_
+#endif  // DEVICE_FIDO_BLE_ADAPTER_MANAGER_H_
diff --git a/device/fido/ble_adapter_power_manager_unittest.cc b/device/fido/ble_adapter_manager_unittest.cc
similarity index 82%
rename from device/fido/ble_adapter_power_manager_unittest.cc
rename to device/fido/ble_adapter_manager_unittest.cc
index 8e62fc5a..fadf3d4 100644
--- a/device/fido/ble_adapter_power_manager_unittest.cc
+++ b/device/fido/ble_adapter_manager_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/ble_adapter_power_manager.h"
+#include "device/fido/ble_adapter_manager.h"
 
 #include <memory>
 
@@ -33,6 +33,9 @@
   MOCK_METHOD1(FidoAuthenticatorAdded,
                void(const FidoAuthenticator& authenticator));
   MOCK_METHOD1(FidoAuthenticatorRemoved, void(base::StringPiece device_id));
+  MOCK_METHOD2(FidoAuthenticatorIdChanged,
+               void(base::StringPiece old_authenticator_id,
+                    std::string new_authenticator_id));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockTransportAvailabilityObserver);
@@ -54,22 +57,21 @@
 
 }  // namespace
 
-class FidoBleAdapterPowerManagerTest : public ::testing::Test {
+class FidoBleAdapterManagerTest : public ::testing::Test {
  public:
-  FidoBleAdapterPowerManagerTest() {
+  FidoBleAdapterManagerTest() {
     BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
   }
 
-  std::unique_ptr<BleAdapterPowerManager> CreateTestBleAdapterPowerManager() {
-    return std::make_unique<BleAdapterPowerManager>(
-        fake_request_handler_.get());
+  std::unique_ptr<BleAdapterManager> CreateTestBleAdapterManager() {
+    return std::make_unique<BleAdapterManager>(fake_request_handler_.get());
   }
 
   MockBluetoothAdapter* adapter() { return adapter_.get(); }
   MockTransportAvailabilityObserver* observer() { return mock_observer_.get(); }
   bool adapter_powered_on_programmatically(
-      const BleAdapterPowerManager& adapter_power_manager) {
-    return adapter_power_manager.adapter_powered_on_programmatically_;
+      const BleAdapterManager& adapter_manager) {
+    return adapter_manager.adapter_powered_on_programmatically_;
   }
 
  protected:
@@ -82,7 +84,7 @@
       std::make_unique<FakeFidoRequestHandlerBase>(mock_observer_.get());
 };
 
-TEST_F(FidoBleAdapterPowerManagerTest, AdapaterNotPresent) {
+TEST_F(FidoBleAdapterManagerTest, AdapaterNotPresent) {
   EXPECT_CALL(*adapter(), IsPresent()).WillOnce(::testing::Return(false));
   EXPECT_CALL(*adapter(), IsPowered()).WillOnce(::testing::Return(false));
   EXPECT_CALL(*adapter(), CanPower()).WillOnce(::testing::Return(false));
@@ -91,14 +93,14 @@
   EXPECT_CALL(*observer(), OnTransportAvailabilityEnumerated(_))
       .WillOnce(::testing::SaveArg<0>(&data));
 
-  CreateTestBleAdapterPowerManager();
+  CreateTestBleAdapterManager();
   scoped_task_environment_.RunUntilIdle();
 
   EXPECT_FALSE(data.is_ble_powered);
   EXPECT_FALSE(data.can_power_on_ble_adapter);
 }
 
-TEST_F(FidoBleAdapterPowerManagerTest, AdapaterPresentAndPowered) {
+TEST_F(FidoBleAdapterManagerTest, AdapaterPresentAndPowered) {
   EXPECT_CALL(*adapter(), IsPresent()).WillOnce(::testing::Return(true));
   EXPECT_CALL(*adapter(), IsPowered()).WillOnce(::testing::Return(true));
   EXPECT_CALL(*adapter(), CanPower()).WillOnce(::testing::Return(false));
@@ -107,14 +109,14 @@
   EXPECT_CALL(*observer(), OnTransportAvailabilityEnumerated(_))
       .WillOnce(::testing::SaveArg<0>(&data));
 
-  CreateTestBleAdapterPowerManager();
+  CreateTestBleAdapterManager();
   scoped_task_environment_.RunUntilIdle();
 
   EXPECT_TRUE(data.is_ble_powered);
   EXPECT_FALSE(data.can_power_on_ble_adapter);
 }
 
-TEST_F(FidoBleAdapterPowerManagerTest, AdapaterPresentAndCanBePowered) {
+TEST_F(FidoBleAdapterManagerTest, AdapaterPresentAndCanBePowered) {
   EXPECT_CALL(*adapter(), IsPresent()).WillOnce(::testing::Return(true));
   EXPECT_CALL(*adapter(), IsPowered()).WillOnce(::testing::Return(false));
   EXPECT_CALL(*adapter(), CanPower()).WillOnce(::testing::Return(true));
@@ -123,15 +125,15 @@
   EXPECT_CALL(*observer(), OnTransportAvailabilityEnumerated(_))
       .WillOnce(::testing::SaveArg<0>(&data));
 
-  CreateTestBleAdapterPowerManager();
+  CreateTestBleAdapterManager();
   scoped_task_environment_.RunUntilIdle();
 
   EXPECT_FALSE(data.is_ble_powered);
   EXPECT_TRUE(data.can_power_on_ble_adapter);
 }
 
-TEST_F(FidoBleAdapterPowerManagerTest, TestSetBluetoothPowerOn) {
-  auto power_manager = CreateTestBleAdapterPowerManager();
+TEST_F(FidoBleAdapterManagerTest, TestSetBluetoothPowerOn) {
+  auto power_manager = CreateTestBleAdapterManager();
   ::testing::InSequence s;
   EXPECT_CALL(*adapter(), SetPowered(true, _, _));
   EXPECT_CALL(*adapter(), SetPowered(false, _, _));
diff --git a/device/fido/fido_discovery.h b/device/fido/fido_discovery.h
index cfc4cad..ef260170c 100644
--- a/device/fido/fido_discovery.h
+++ b/device/fido/fido_discovery.h
@@ -9,6 +9,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/component_export.h"
@@ -58,6 +59,11 @@
     virtual void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) = 0;
     virtual void DeviceRemoved(FidoDiscovery* discovery,
                                FidoDevice* device) = 0;
+    // Invoked when address of the connected FIDO Bluetooth device changes due
+    // to pairing.
+    virtual void DeviceIdChanged(FidoDiscovery* discovery,
+                                 const std::string& previous_id,
+                                 std::string new_id) = 0;
   };
 
   // Factory functions to construct an instance that discovers authenticators on
diff --git a/device/fido/fido_request_handler_base.cc b/device/fido/fido_request_handler_base.cc
index 57428aa..402c5092 100644
--- a/device/fido/fido_request_handler_base.cc
+++ b/device/fido/fido_request_handler_base.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_piece.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
-#include "device/fido/ble_adapter_power_manager.h"
+#include "device/fido/ble_adapter_manager.h"
 #include "device/fido/fido_device.h"
 #include "device/fido/fido_task.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -168,10 +168,10 @@
 }
 
 void FidoRequestHandlerBase::PowerOnBluetoothAdapter() {
-  if (!bluetooth_power_manager_)
+  if (!bluetooth_adapter_manager_)
     return;
 
-  bluetooth_power_manager_->SetAdapterPower(true /* set_power_on */);
+  bluetooth_adapter_manager_->SetAdapterPower(true /* set_power_on */);
 }
 
 base::WeakPtr<FidoRequestHandlerBase> FidoRequestHandlerBase::GetWeakPtr() {
@@ -208,6 +208,21 @@
     observer_->FidoAuthenticatorRemoved(device->GetId());
 }
 
+void FidoRequestHandlerBase::DeviceIdChanged(FidoDiscovery* discovery,
+                                             const std::string& previous_id,
+                                             std::string new_id) {
+  DCHECK_EQ(FidoTransportProtocol::kBluetoothLowEnergy, discovery->transport());
+  auto it = active_authenticators_.find(previous_id);
+  if (it == active_authenticators_.end())
+    return;
+
+  active_authenticators_.emplace(new_id, std::move(it->second));
+  active_authenticators_.erase(it);
+
+  if (observer_)
+    observer_->FidoAuthenticatorIdChanged(previous_id, std::move(new_id));
+}
+
 void FidoRequestHandlerBase::AddAuthenticator(
     std::unique_ptr<FidoAuthenticator> authenticator) {
   DCHECK(authenticator &&
@@ -272,7 +287,7 @@
 }
 
 void FidoRequestHandlerBase::ConstructBleAdapterPowerManager() {
-  bluetooth_power_manager_ = std::make_unique<BleAdapterPowerManager>(this);
+  bluetooth_adapter_manager_ = std::make_unique<BleAdapterManager>(this);
 }
 
 }  // namespace device
diff --git a/device/fido/fido_request_handler_base.h b/device/fido/fido_request_handler_base.h
index aed8c41..0ab206f4 100644
--- a/device/fido/fido_request_handler_base.h
+++ b/device/fido/fido_request_handler_base.h
@@ -29,7 +29,7 @@
 
 namespace device {
 
-class BleAdapterPowerManager;
+class BleAdapterManager;
 class FidoAuthenticator;
 class FidoDevice;
 class FidoTask;
@@ -110,6 +110,9 @@
     virtual void FidoAuthenticatorAdded(
         const FidoAuthenticator& authenticator) = 0;
     virtual void FidoAuthenticatorRemoved(base::StringPiece device_id) = 0;
+    virtual void FidoAuthenticatorIdChanged(
+        base::StringPiece old_authenticator_id,
+        std::string new_authenticator_id) = 0;
   };
 
   // TODO(https://crbug.com/769631): Remove the dependency on Connector once
@@ -181,9 +184,14 @@
   TransportAvailabilityObserver* observer() const { return observer_; }
 
  private:
+  friend class FidoRequestHandlerTest;
+
   // FidoDiscovery::Observer
   void DeviceAdded(FidoDiscovery* discovery, FidoDevice* device) final;
   void DeviceRemoved(FidoDiscovery* discovery, FidoDevice* device) final;
+  void DeviceIdChanged(FidoDiscovery* discovery,
+                       const std::string& previous_id,
+                       std::string new_id) final;
 
   void AddAuthenticator(std::unique_ptr<FidoAuthenticator> authenticator);
   void NotifyObserverTransportAvailability();
@@ -200,7 +208,7 @@
   TransportAvailabilityObserver* observer_ = nullptr;
   TransportAvailabilityInfo transport_availability_info_;
   base::RepeatingClosure notify_observer_callback_;
-  std::unique_ptr<BleAdapterPowerManager> bluetooth_power_manager_;
+  std::unique_ptr<BleAdapterManager> bluetooth_adapter_manager_;
 
   base::WeakPtrFactory<FidoRequestHandlerBase> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(FidoRequestHandlerBase);
diff --git a/device/fido/fido_request_handler_unittest.cc b/device/fido/fido_request_handler_unittest.cc
index d617fb1d..3daa0b1 100644
--- a/device/fido/fido_request_handler_unittest.cc
+++ b/device/fido/fido_request_handler_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -53,6 +54,8 @@
  public:
   using TransportAvailabilityNotificationReceiver = test::TestCallbackReceiver<
       FidoRequestHandlerBase::TransportAvailabilityInfo>;
+  using AuthenticatorIdChangeNotificationReceiver =
+      test::TestCallbackReceiver<std::string>;
 
   TestTransportAvailabilityObserver() {}
   ~TestTransportAvailabilityObserver() override {}
@@ -72,6 +75,14 @@
     }
   }
 
+  void WaitForAuthenticatorIdChangeNotification(
+      base::StringPiece expected_new_authenticator_id) {
+    authenticator_id_change_notification_receiver_.WaitForCallback();
+    auto result =
+        std::get<0>(*authenticator_id_change_notification_receiver_.result());
+    EXPECT_EQ(expected_new_authenticator_id, result);
+  }
+
  protected:
   // FidoRequestHandlerBase::TransportAvailabilityObserver:
   void OnTransportAvailabilityEnumerated(
@@ -88,10 +99,17 @@
   void FidoAuthenticatorAdded(const FidoAuthenticator& authenticator) override {
   }
   void FidoAuthenticatorRemoved(base::StringPiece device_id) override {}
+  void FidoAuthenticatorIdChanged(base::StringPiece old_authenticator_id,
+                                  std::string new_authenticator_id) override {
+    authenticator_id_change_notification_receiver_.callback().Run(
+        std::move(new_authenticator_id));
+  }
 
  private:
   TransportAvailabilityNotificationReceiver
       transport_availability_notification_receiver_;
+  AuthenticatorIdChangeNotificationReceiver
+      authenticator_id_change_notification_receiver_;
 
   DISALLOW_COPY_AND_ASSIGN(TestTransportAvailabilityObserver);
 };
@@ -223,6 +241,13 @@
     return handler;
   }
 
+  void ChangeAuthenticatorId(FakeFidoRequestHandler* request_handler,
+                             FidoDevice* device,
+                             std::string new_authenticator_id) {
+    request_handler->DeviceIdChanged(ble_discovery_, device->GetId(),
+                                     std::move(new_authenticator_id));
+  }
+
   test::FakeFidoDiscovery* discovery() const { return discovery_; }
   test::FakeFidoDiscovery* ble_discovery() const { return ble_discovery_; }
   scoped_refptr<::testing::NiceMock<MockBluetoothAdapter>> adapter() {
@@ -587,4 +612,20 @@
        FidoTransportProtocol::kBluetoothLowEnergy});
 }
 
+TEST_F(FidoRequestHandlerTest, EmbedderNotifiedWhenAuthenticatorIdChanges) {
+  static constexpr char kNewAuthenticatorId[] = "new_authenticator_id";
+  TestTransportAvailabilityObserver observer;
+  auto request_handler = CreateFakeHandler();
+  request_handler->set_observer(&observer);
+  ble_discovery()->WaitForCallToStartAndSimulateSuccess();
+
+  auto device = std::make_unique<MockFidoDevice>();
+  auto* device_ptr = device.get();
+  EXPECT_CALL(*device, GetId()).WillRepeatedly(testing::Return("device0"));
+  discovery()->AddDevice(std::move(device));
+
+  ChangeAuthenticatorId(request_handler.get(), device_ptr, kNewAuthenticatorId);
+  observer.WaitForAuthenticatorIdChangeNotification(kNewAuthenticatorId);
+}
+
 }  // namespace device
diff --git a/device/fido/mac/authenticator_config.h b/device/fido/mac/authenticator_config.h
new file mode 100644
index 0000000..2981f5ee
--- /dev/null
+++ b/device/fido/mac/authenticator_config.h
@@ -0,0 +1,32 @@
+// 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 DEVICE_FIDO_MAC_AUTHENTICATOR_CONFIG_H_
+#define DEVICE_FIDO_MAC_AUTHENTICATOR_CONFIG_H_
+
+#include <string>
+
+#include "base/component_export.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+struct COMPONENT_EXPORT(DEVICE_FIDO) AuthenticatorConfig {
+  // The keychain-access-group value used for WebAuthn credentials
+  // stored in the macOS keychain by the built-in Touch ID
+  // authenticator.
+  std::string keychain_access_group;
+  // The secret used to derive key material when encrypting WebAuthn
+  // credential metadata for storage in the macOS keychain. Chrome returns
+  // different secrets for each user profile in order to logically separate
+  // credentials per profile.
+  std::string metadata_secret;
+};
+
+}  // namespace mac
+}  // namespace fido
+}  // namespace device
+
+#endif  // DEVICE_FIDO_MAC_AUTHENTICATOR_CONFIG_H_
diff --git a/device/fido/mac/browsing_data_deletion.h b/device/fido/mac/browsing_data_deletion.h
deleted file mode 100644
index decf340..0000000
--- a/device/fido/mac/browsing_data_deletion.h
+++ /dev/null
@@ -1,48 +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 DEVICE_FIDO_MAC_BROWSING_DATA_DELETION_H_
-#define DEVICE_FIDO_MAC_BROWSING_DATA_DELETION_H_
-
-#include <string>
-
-#include "base/component_export.h"
-#include "base/time/time.h"
-
-namespace device {
-namespace fido {
-namespace mac {
-
-// DeleteWebAuthnCredentiuals deletes Touch ID authenticator credentials from
-// the macOS keychain that were created within the given time interval and with
-// the given metadata secret (which is tied to a browser profile). The
-// |keychain_access_group| parameter is an identifier tied to Chrome's code
-// signing identity that identifies the set of all keychain items associated
-// with the Touch ID WebAuthentication authenticator.
-//
-// Returns false if any attempt to delete a credential failed (but others may
-// still have succeeded), and true otherwise.
-//
-// On platforms where Touch ID is not supported, or when the Touch ID WebAuthn
-// authenticator feature flag is disabled, this method does nothing and returns
-// true.
-bool COMPONENT_EXPORT(DEVICE_FIDO)
-    DeleteWebAuthnCredentials(const std::string& keychain_access_group,
-                              const std::string& profile_metadata_secret,
-                              base::Time created_not_before,
-                              base::Time created_not_after);
-
-// CountWebAuthnCredentials returns the number of credentials that would get
-// deleted by a call to |DeleteWebAuthnCredentials| with identical arguments.
-size_t COMPONENT_EXPORT(DEVICE_FIDO)
-    CountWebAuthnCredentials(const std::string& keychain_access_group,
-                             const std::string& profile_metadata_secret,
-                             base::Time created_not_before,
-                             base::Time created_not_after);
-
-}  // namespace mac
-}  // namespace fido
-}  // namespace device
-
-#endif  // DEVICE_FIDO_MAC_BROWSING_DATA_DELETION_H_
diff --git a/device/fido/mac/browsing_data_deletion_unittest.mm b/device/fido/mac/browsing_data_deletion_unittest.mm
index 5d80d69..e1a6d6b 100644
--- a/device/fido/mac/browsing_data_deletion_unittest.mm
+++ b/device/fido/mac/browsing_data_deletion_unittest.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/mac/browsing_data_deletion.h"
+#include "device/fido/mac/credential_store.h"
 
 #include <Foundation/Foundation.h>
 #include <Security/Security.h>
@@ -17,6 +17,7 @@
 #include "device/fido/ctap_make_credential_request.h"
 #include "device/fido/fido_constants.h"
 #include "device/fido/mac/authenticator.h"
+#include "device/fido/mac/authenticator_config.h"
 #include "device/fido/mac/keychain.h"
 #include "device/fido/test_callback_receiver.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -149,14 +150,16 @@
 
   bool DeleteCredentials() { return DeleteCredentials(kMetadataSecret); }
   bool DeleteCredentials(const std::string& metadata_secret) {
-    return DeleteWebAuthnCredentials(kKeychainAccessGroup, metadata_secret,
-                                     base::Time(), base::Time::Max());
+    return TouchIdCredentialStore(
+               AuthenticatorConfig{kKeychainAccessGroup, metadata_secret})
+        .DeleteCredentials(base::Time(), base::Time::Max());
   }
 
   size_t CountCredentials() { return CountCredentials(kMetadataSecret); }
   size_t CountCredentials(const std::string& metadata_secret) {
-    return CountWebAuthnCredentials(kKeychainAccessGroup, metadata_secret,
-                                    base::Time(), base::Time::Max());
+    return TouchIdCredentialStore(
+               AuthenticatorConfig{kKeychainAccessGroup, metadata_secret})
+        .CountCredentials(base::Time(), base::Time::Max());
   }
 
   base::test::ScopedFeatureList scoped_feature_list_;
diff --git a/device/fido/mac/credential_store.h b/device/fido/mac/credential_store.h
new file mode 100644
index 0000000..441b2fb
--- /dev/null
+++ b/device/fido/mac/credential_store.h
@@ -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.
+
+#ifndef DEVICE_FIDO_MAC_CREDENTIAL_STORE_H_
+#define DEVICE_FIDO_MAC_CREDENTIAL_STORE_H_
+
+#include "base/component_export.h"
+#include "device/fido/mac/authenticator_config.h"
+#include "device/fido/platform_credential_store.h"
+
+namespace device {
+namespace fido {
+namespace mac {
+
+class COMPONENT_EXPORT(DEVICE_FIDO) TouchIdCredentialStore
+    : public ::device::fido::PlatformCredentialStore {
+ public:
+  TouchIdCredentialStore(AuthenticatorConfig config);
+  ~TouchIdCredentialStore() override;
+
+  // DeleteCredentials deletes Touch ID authenticator credentials from
+  // the macOS keychain that were created within the given time interval and
+  // with the given metadata secret (which is tied to a browser profile). The
+  // |keychain_access_group| parameter is an identifier tied to Chrome's code
+  // signing identity that identifies the set of all keychain items associated
+  // with the Touch ID WebAuthentication authenticator.
+  //
+  // Returns false if any attempt to delete a credential failed (but others may
+  // still have succeeded), and true otherwise.
+  //
+  // On platforms where Touch ID is not supported, or when the Touch ID WebAuthn
+  // authenticator feature flag is disabled, this method does nothing and
+  // returns true.
+  bool DeleteCredentials(base::Time created_not_before,
+                         base::Time created_not_after) override;
+
+  // CountCredentials returns the number of credentials that would get
+  // deleted by a call to |DeleteWebAuthnCredentials| with identical arguments.
+  size_t CountCredentials(base::Time created_not_before,
+                          base::Time created_not_after) override;
+
+ private:
+  AuthenticatorConfig config_;
+
+  DISALLOW_COPY_AND_ASSIGN(TouchIdCredentialStore);
+};
+
+}  // namespace mac
+}  // namespace fido
+}  // namespace device
+
+#endif  // DEVICE_FIDO_MAC_CREDENTIAL_STORE_H_
diff --git a/device/fido/mac/browsing_data_deletion.mm b/device/fido/mac/credential_store.mm
similarity index 82%
rename from device/fido/mac/browsing_data_deletion.mm
rename to device/fido/mac/credential_store.mm
index 9826118..19f5749 100644
--- a/device/fido/mac/browsing_data_deletion.mm
+++ b/device/fido/mac/credential_store.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "device/fido/mac/browsing_data_deletion.h"
+#include "device/fido/mac/credential_store.h"
 
 #include <string>
 
@@ -17,8 +17,6 @@
 #include "base/optional.h"
 #include "base/stl_util.h"
 #include "base/strings/sys_string_conversions.h"
-#include "base/time/time.h"
-#include "build/build_config.h"
 #include "device/base/features.h"
 #include "device/fido/mac/credential_metadata.h"
 #include "device/fido/mac/keychain.h"
@@ -53,7 +51,7 @@
 }
 base::Optional<std::vector<base::ScopedCFTypeRef<CFDictionaryRef>>>
 QueryKeychainItemsForProfile(const std::string& keychain_access_group,
-                             const std::string& profile_metadata_secret,
+                             const std::string& metadata_secret,
                              base::Time created_not_before,
                              base::Time created_not_after)
     API_AVAILABLE(macosx(10.12.2)) {
@@ -117,7 +115,7 @@
       continue;
     }
     base::Optional<std::string> opt_rp_id = CredentialMetadata::DecodeRpId(
-        profile_metadata_secret, base::SysCFStringRefToUTF8(sec_attr_label));
+        metadata_secret, base::SysCFStringRefToUTF8(sec_attr_label));
     if (!opt_rp_id) {
       DVLOG(1) << "key doesn't belong to this profile";
       continue;
@@ -133,15 +131,15 @@
 }
 
 bool DoDeleteWebAuthnCredentials(const std::string& keychain_access_group,
-                                 const std::string& profile_metadata_secret,
+                                 const std::string& metadata_secret,
                                  base::Time created_not_before,
                                  base::Time created_not_after)
     API_AVAILABLE(macosx(10.12.2)) {
   bool result = true;
   base::Optional<std::vector<base::ScopedCFTypeRef<CFDictionaryRef>>>
-      keychain_items = QueryKeychainItemsForProfile(
-          keychain_access_group, profile_metadata_secret, created_not_before,
-          created_not_after);
+      keychain_items =
+          QueryKeychainItemsForProfile(keychain_access_group, metadata_secret,
+                                       created_not_before, created_not_after);
   if (!keychain_items) {
     return false;
   }
@@ -177,14 +175,14 @@
 }
 
 size_t DoCountWebAuthnCredentials(const std::string& keychain_access_group,
-                                  const std::string& profile_metadata_secret,
+                                  const std::string& metadata_secret,
                                   base::Time created_not_before,
                                   base::Time created_not_after)
     API_AVAILABLE(macosx(10.12.2)) {
   base::Optional<std::vector<base::ScopedCFTypeRef<CFDictionaryRef>>>
-      keychain_items = QueryKeychainItemsForProfile(
-          keychain_access_group, profile_metadata_secret, created_not_before,
-          created_not_after);
+      keychain_items =
+          QueryKeychainItemsForProfile(keychain_access_group, metadata_secret,
+                                       created_not_before, created_not_after);
   if (!keychain_items) {
     DLOG(ERROR) << "Failed to query credentials in keychain";
     return 0;
@@ -194,37 +192,33 @@
 }
 }  // namespace
 
-bool DeleteWebAuthnCredentials(const std::string& keychain_access_group,
-                               const std::string& profile_metadata_secret,
-                               base::Time created_not_before,
-                               base::Time created_not_after) {
-#if defined(OS_MACOSX)
+TouchIdCredentialStore::TouchIdCredentialStore(AuthenticatorConfig config)
+    : config_(std::move(config)) {}
+TouchIdCredentialStore::~TouchIdCredentialStore() = default;
+
+bool TouchIdCredentialStore::DeleteCredentials(base::Time created_not_before,
+                                               base::Time created_not_after) {
   if (base::FeatureList::IsEnabled(device::kWebAuthTouchId)) {
     // Touch ID uses macOS APIs available in 10.12.2 or newer. No need to check
     // for credentials in lower OS versions.
     if (__builtin_available(macos 10.12.2, *)) {
-      return DoDeleteWebAuthnCredentials(keychain_access_group,
-                                         profile_metadata_secret,
+      return DoDeleteWebAuthnCredentials(config_.keychain_access_group,
+                                         config_.metadata_secret,
                                          created_not_before, created_not_after);
     }
   }
-#endif  // defined(OS_MACOSX)
   return true;
 }
 
-size_t CountWebAuthnCredentials(const std::string& keychain_access_group,
-                                const std::string& profile_metadata_secret,
-                                base::Time created_not_before,
-                                base::Time created_not_after) {
-#if defined(OS_MACOSX)
+size_t TouchIdCredentialStore::CountCredentials(base::Time created_not_before,
+                                                base::Time created_not_after) {
   if (base::FeatureList::IsEnabled(device::kWebAuthTouchId)) {
     if (__builtin_available(macos 10.12.2, *)) {
-      return DoCountWebAuthnCredentials(keychain_access_group,
-                                        profile_metadata_secret,
+      return DoCountWebAuthnCredentials(config_.keychain_access_group,
+                                        config_.metadata_secret,
                                         created_not_before, created_not_after);
     }
   }
-#endif  // defined(OS_MACOSX)
   return 0;
 }
 
diff --git a/device/fido/mock_fido_discovery_observer.h b/device/fido/mock_fido_discovery_observer.h
index 8d4ecb7c..3362c5e 100644
--- a/device/fido/mock_fido_discovery_observer.h
+++ b/device/fido/mock_fido_discovery_observer.h
@@ -5,6 +5,8 @@
 #ifndef DEVICE_FIDO_MOCK_FIDO_DISCOVERY_OBSERVER_H_
 #define DEVICE_FIDO_MOCK_FIDO_DISCOVERY_OBSERVER_H_
 
+#include <string>
+
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "device/fido/fido_discovery.h"
@@ -23,6 +25,8 @@
   MOCK_METHOD2(DiscoveryStopped, void(FidoDiscovery*, bool));
   MOCK_METHOD2(DeviceAdded, void(FidoDiscovery*, FidoDevice*));
   MOCK_METHOD2(DeviceRemoved, void(FidoDiscovery*, FidoDevice*));
+  MOCK_METHOD3(DeviceIdChanged,
+               void(FidoDiscovery*, const std::string&, std::string));
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MockFidoDiscoveryObserver);
diff --git a/device/fido/platform_credential_store.h b/device/fido/platform_credential_store.h
new file mode 100644
index 0000000..55fc7c23
--- /dev/null
+++ b/device/fido/platform_credential_store.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef DEVICE_FIDO_PLATFORM_CREDENTIAL_STORE_H_
+#define DEVICE_FIDO_PLATFORM_CREDENTIAL_STORE_H_
+
+#include "base/component_export.h"
+#include "base/time/time.h"
+
+namespace device {
+namespace fido {
+
+// The PlatformCredentialStore interface wraps methods for deleting WebAuthn
+// credentials that belong to authenticators integrated into Chrome (currently
+// only the TouchIdAuthenticator in //device/fido/mac).
+class COMPONENT_EXPORT(DEVICE_FIDO) PlatformCredentialStore {
+ public:
+  virtual ~PlatformCredentialStore() = default;
+
+  // DeleteCredentials deletes WebAuthn credentials that were created within the
+  // given time interval from local storage.
+  //
+  // Returns false if any attempt to delete a credential failed (but others may
+  // still have succeeded), and true otherwise.
+  virtual bool DeleteCredentials(base::Time created_not_before,
+                                 base::Time created_not_after) = 0;
+
+  // CountCredentials returns the number of credentials that would get deleted
+  // by a call to |DeleteCredentials| with identical arguments.
+  virtual size_t CountCredentials(base::Time created_not_before,
+                                  base::Time created_not_after) = 0;
+};
+
+}  // namespace fido
+}  // namespace device
+
+#endif  // DEVICE_FIDO_PLATFORM_CREDENTIAL_STORE_H_
diff --git a/device/gamepad/gamepad_data_fetcher_manager.cc b/device/gamepad/gamepad_data_fetcher_manager.cc
index 985469f..71c17ea 100644
--- a/device/gamepad/gamepad_data_fetcher_manager.cc
+++ b/device/gamepad/gamepad_data_fetcher_manager.cc
@@ -38,8 +38,7 @@
   if (provider_)
     provider_->RemoveSourceGamepadDataFetcher(source);
 
-  for (FactoryVector::iterator it = factories_.begin();
-       it != factories_.end();) {
+  for (auto it = factories_.begin(); it != factories_.end();) {
     if ((*it)->source() == source) {
       delete (*it);
       it = factories_.erase(it);
diff --git a/device/gamepad/gamepad_provider.cc b/device/gamepad/gamepad_provider.cc
index fb42a34..8b7b1b0 100644
--- a/device/gamepad/gamepad_provider.cc
+++ b/device/gamepad/gamepad_provider.cc
@@ -226,8 +226,7 @@
 
 GamepadDataFetcher* GamepadProvider::GetSourceGamepadDataFetcher(
     GamepadSource source) {
-  for (GamepadFetcherVector::iterator it = data_fetchers_.begin();
-       it != data_fetchers_.end();) {
+  for (auto it = data_fetchers_.begin(); it != data_fetchers_.end();) {
     if ((*it)->source() == source) {
       return it->get();
     } else {
@@ -251,8 +250,7 @@
 void GamepadProvider::DoRemoveSourceGamepadDataFetcher(GamepadSource source) {
   DCHECK(polling_thread_->task_runner()->BelongsToCurrentThread());
 
-  for (GamepadFetcherVector::iterator it = data_fetchers_.begin();
-       it != data_fetchers_.end();) {
+  for (auto it = data_fetchers_.begin(); it != data_fetchers_.end();) {
     if ((*it)->source() == source) {
       it = data_fetchers_.erase(it);
     } else {
diff --git a/device/gamepad/gamepad_service.cc b/device/gamepad/gamepad_service.cc
index 37aa3070..342dc4d4 100644
--- a/device/gamepad/gamepad_service.cc
+++ b/device/gamepad/gamepad_service.cc
@@ -118,7 +118,7 @@
 void GamepadService::RemoveConsumer(device::GamepadConsumer* consumer) {
   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
-  ConsumerSet::iterator it = consumers_.find(consumer);
+  auto it = consumers_.find(consumer);
   if (it->is_active && --num_active_consumers_ == 0)
     provider_->Pause();
   consumers_.erase(it);
@@ -152,8 +152,7 @@
 void GamepadService::OnGamepadConnected(uint32_t index, const Gamepad& pad) {
   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
-  for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end();
-       ++it) {
+  for (auto it = consumers_.begin(); it != consumers_.end(); ++it) {
     if (it->did_observe_user_gesture && it->is_active)
       it->consumer->OnGamepadConnected(index, pad);
   }
@@ -162,8 +161,7 @@
 void GamepadService::OnGamepadDisconnected(uint32_t index, const Gamepad& pad) {
   DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
 
-  for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end();
-       ++it) {
+  for (auto it = consumers_.begin(); it != consumers_.end(); ++it) {
     if (it->did_observe_user_gesture && it->is_active)
       it->consumer->OnGamepadDisconnected(index, pad);
   }
@@ -213,8 +211,7 @@
   if (!provider_ || num_active_consumers_ == 0)
     return;
 
-  for (ConsumerSet::iterator it = consumers_.begin(); it != consumers_.end();
-       ++it) {
+  for (auto it = consumers_.begin(); it != consumers_.end(); ++it) {
     if (!it->did_observe_user_gesture && it->is_active) {
       const ConsumerInfo& info = *it;
       info.did_observe_user_gesture = true;
diff --git a/device/usb/usb_descriptors.cc b/device/usb/usb_descriptors.cc
index ba254f6c..3b6502b 100644
--- a/device/usb/usb_descriptors.cc
+++ b/device/usb/usb_descriptors.cc
@@ -57,7 +57,7 @@
 void ParseInterfaceAssociationDescriptors(
     const std::vector<uint8_t>& buffer,
     std::vector<UsbInterfaceAssociationDescriptor>* functions) {
-  std::vector<uint8_t>::const_iterator it = buffer.begin();
+  auto it = buffer.begin();
 
   while (it != buffer.end()) {
     // All descriptors must be at least 2 byte which means the length and type
@@ -422,8 +422,7 @@
   UsbInterfaceDescriptor* last_interface = nullptr;
   UsbEndpointDescriptor* last_endpoint = nullptr;
 
-  for (std::vector<uint8_t>::const_iterator it = buffer.begin();
-       it != buffer.end();
+  for (auto it = buffer.begin(); it != buffer.end();
        /* incremented internally */) {
     const uint8_t* data = &it[0];
     uint8_t length = data[0];
diff --git a/device/usb/webusb_descriptors.cc b/device/usb/webusb_descriptors.cc
index 046d19de..8bd69a5 100644
--- a/device/usb/webusb_descriptors.cc
+++ b/device/usb/webusb_descriptors.cc
@@ -141,8 +141,8 @@
   }
 
   uint8_t num_device_caps = bytes[4];
-  std::vector<uint8_t>::const_iterator it = bytes.begin();
-  std::vector<uint8_t>::const_iterator end = it + total_length;
+  auto it = bytes.begin();
+  auto end = it + total_length;
   std::advance(it, 5);
 
   uint8_t length = 0;
diff --git a/device/vr/oculus/oculus_device.cc b/device/vr/oculus/oculus_device.cc
index 5996900..8b8929f7 100644
--- a/device/vr/oculus/oculus_device.cc
+++ b/device/vr/oculus/oculus_device.cc
@@ -88,6 +88,7 @@
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       exclusive_controller_binding_(this),
       gamepad_provider_factory_binding_(this),
+      compositor_host_binding_(this),
       weak_ptr_factory_(this) {
   StartOvrSession();
   if (!session_) {
@@ -105,6 +106,12 @@
   return ret;
 }
 
+mojom::XRCompositorHostPtr OculusDevice::BindCompositorHost() {
+  mojom::XRCompositorHostPtr ret;
+  compositor_host_binding_.Bind(mojo::MakeRequest(&ret));
+  return ret;
+}
+
 OculusDevice::~OculusDevice() {
   // Wait for the render loop to stop before completing destruction. This will
   // ensure that bindings are closed on the correct thread.
@@ -141,6 +148,13 @@
                                     base::Unretained(render_loop_.get()),
                                     std::move(provider_request_)));
     }
+
+    if (overlay_request_) {
+      render_loop_->task_runner()->PostTask(
+          FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
+                                    base::Unretained(render_loop_.get()),
+                                    std::move(overlay_request_)));
+    }
   }
 
   auto on_request_present_result =
@@ -258,4 +272,16 @@
   }
 }
 
+void OculusDevice::CreateImmersiveOverlay(
+    mojom::ImmersiveOverlayRequest overlay_request) {
+  if (render_loop_->IsRunning()) {
+    render_loop_->task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
+                                  base::Unretained(render_loop_.get()),
+                                  std::move(overlay_request)));
+  } else {
+    overlay_request_ = std::move(overlay_request);
+  }
+}
+
 }  // namespace device
diff --git a/device/vr/oculus/oculus_device.h b/device/vr/oculus/oculus_device.h
index 1dacbda..95b514f4 100644
--- a/device/vr/oculus/oculus_device.h
+++ b/device/vr/oculus/oculus_device.h
@@ -21,7 +21,8 @@
 class DEVICE_VR_EXPORT OculusDevice
     : public VRDeviceBase,
       public mojom::XRSessionController,
-      public mojom::IsolatedXRGamepadProviderFactory {
+      public mojom::IsolatedXRGamepadProviderFactory,
+      public mojom::XRCompositorHost {
  public:
   explicit OculusDevice();
   ~OculusDevice() override;
@@ -39,6 +40,7 @@
   bool IsInitialized() { return !!session_; }
 
   mojom::IsolatedXRGamepadProviderFactoryPtr BindGamepadFactory();
+  mojom::XRCompositorHostPtr BindCompositorHost();
 
  private:
   // XRSessionController
@@ -50,6 +52,10 @@
   void GetIsolatedXRGamepadProvider(
       mojom::IsolatedXRGamepadProviderRequest provider_request) override;
 
+  // XRCompositorHost
+  void CreateImmersiveOverlay(
+      mojom::ImmersiveOverlayRequest overlay_request) override;
+
   void OnPresentationEnded();
   void StartOvrSession();
   void StopOvrSession();
@@ -63,6 +69,9 @@
       gamepad_provider_factory_binding_;
   mojom::IsolatedXRGamepadProviderRequest provider_request_;
 
+  mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
+  mojom::ImmersiveOverlayRequest overlay_request_;
+
   base::WeakPtrFactory<OculusDevice> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(OculusDevice);
diff --git a/device/vr/openvr/openvr_device.cc b/device/vr/openvr/openvr_device.cc
index 4ec45a9..d3be3f9 100644
--- a/device/vr/openvr/openvr_device.cc
+++ b/device/vr/openvr/openvr_device.cc
@@ -132,6 +132,7 @@
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       exclusive_controller_binding_(this),
       gamepad_provider_factory_binding_(this),
+      compositor_host_binding_(this),
       weak_ptr_factory_(this) {
   // Initialize OpenVR.
   openvr_ = std::make_unique<OpenVRWrapper>(false /* presenting */);
@@ -153,6 +154,12 @@
   return ret;
 }
 
+mojom::XRCompositorHostPtr OpenVRDevice::BindCompositorHost() {
+  mojom::XRCompositorHostPtr ret;
+  compositor_host_binding_.Bind(mojo::MakeRequest(&ret));
+  return ret;
+}
+
 OpenVRDevice::~OpenVRDevice() {
   Shutdown();
 }
@@ -187,6 +194,13 @@
                                     base::Unretained(render_loop_.get()),
                                     std::move(provider_request_)));
     }
+
+    if (overlay_request_) {
+      render_loop_->task_runner()->PostTask(
+          FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
+                                    base::Unretained(render_loop_.get()),
+                                    std::move(overlay_request_)));
+    }
   }
 
   // We are done using OpenVR until the presentation session ends.
@@ -254,6 +268,18 @@
   }
 }
 
+void OpenVRDevice::CreateImmersiveOverlay(
+    mojom::ImmersiveOverlayRequest overlay_request) {
+  if (render_loop_->IsRunning()) {
+    render_loop_->task_runner()->PostTask(
+        FROM_HERE, base::BindOnce(&XRCompositorCommon::RequestOverlay,
+                                  base::Unretained(render_loop_.get()),
+                                  std::move(overlay_request)));
+  } else {
+    overlay_request_ = std::move(overlay_request);
+  }
+}
+
 // XRSessionController
 void OpenVRDevice::SetFrameDataRestricted(bool restricted) {
   // Presentation sessions can not currently be restricted.
diff --git a/device/vr/openvr/openvr_device.h b/device/vr/openvr/openvr_device.h
index 0d4fe89a..1360a8c 100644
--- a/device/vr/openvr/openvr_device.h
+++ b/device/vr/openvr/openvr_device.h
@@ -21,7 +21,8 @@
 class DEVICE_VR_EXPORT OpenVRDevice
     : public VRDeviceBase,
       public mojom::XRSessionController,
-      public mojom::IsolatedXRGamepadProviderFactory {
+      public mojom::IsolatedXRGamepadProviderFactory,
+      public mojom::XRCompositorHost {
  public:
   OpenVRDevice();
   ~OpenVRDevice() override;
@@ -42,6 +43,7 @@
   bool IsInitialized() { return !!openvr_; }
 
   mojom::IsolatedXRGamepadProviderFactoryPtr BindGamepadFactory();
+  mojom::XRCompositorHostPtr BindCompositorHost();
 
  private:
   // VRDeviceBase
@@ -55,6 +57,10 @@
   void GetIsolatedXRGamepadProvider(
       mojom::IsolatedXRGamepadProviderRequest provider_request) override;
 
+  // XRCompositorHost
+  void CreateImmersiveOverlay(
+      mojom::ImmersiveOverlayRequest overlay_request) override;
+
   void OnPresentingControllerMojoConnectionError();
   void OnPresentationEnded();
 
@@ -68,6 +74,9 @@
       gamepad_provider_factory_binding_;
   mojom::IsolatedXRGamepadProviderRequest provider_request_;
 
+  mojo::Binding<mojom::XRCompositorHost> compositor_host_binding_;
+  mojom::ImmersiveOverlayRequest overlay_request_;
+
   base::WeakPtrFactory<OpenVRDevice> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(OpenVRDevice);
diff --git a/device/vr/public/mojom/isolated_xr_service.mojom b/device/vr/public/mojom/isolated_xr_service.mojom
index 95f4409..3fede7aa 100644
--- a/device/vr/public/mojom/isolated_xr_service.mojom
+++ b/device/vr/public/mojom/isolated_xr_service.mojom
@@ -6,6 +6,7 @@
 
 import "device/vr/public/mojom/vr_service.mojom";
 import "mojo/public/mojom/base/time.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
 
 const string kVrIsolatedServiceName = "xr_device_service";
 
@@ -139,6 +140,31 @@
   GetIsolatedXRGamepadProvider(IsolatedXRGamepadProvider& provider);
 };
 
+// Represents an overlay that the browser may show on top of or instead of WebXR
+// content.  Consumed in the browser process, and implemented in the XRRuntime
+// process.
+interface ImmersiveOverlay {
+  // Request a pose.  If there is WebXR and an overlay visible at the same time,
+  // the same pose will be given to both.
+  RequestNextOverlayPose() => (device.mojom.XRFrameData pose);
+
+  // Submit a frame to show in the headset.  Only can be called when an overlay
+  // is visible.  The frame will be composited on top of WebXR content.
+  SubmitOverlayTexture(int16 frame_id, handle texture,
+      gfx.mojom.RectF left_bounds, gfx.mojom.RectF right_bounds) =>
+      (bool success);
+
+  // Allows the browser to hide WebXR content or overlays temporarily.
+  SetOverlayAndWebXRVisibility(bool overlay_visible, bool webxr_visible);
+};
+
+// XRCompositorHost lives in the XRRuntime process, and allows the browser to
+// obtain an ImmersiveOverlay to show overlay UI.  The obtained overlay will
+// disconnect when presentation ends.
+interface XRCompositorHost {
+  CreateImmersiveOverlay(ImmersiveOverlay& overlay);
+};
+
 // Notify the browser process about a set of runtimes.  The browser process
 // implements this interface to be notified about runtime changes from the XR
 // device service.
@@ -147,6 +173,7 @@
   // attached and become available.
   OnDeviceAdded(XRRuntime runtime,
       IsolatedXRGamepadProviderFactory gamepad_factory,
+      XRCompositorHost compositor_host,
       device.mojom.VRDisplayInfo display_info);
 
   // Called when runtimes become unavailable - for example if the hardware is
diff --git a/device/vr/windows/compositor_base.cc b/device/vr/windows/compositor_base.cc
index da9550a..698d6ac8 100644
--- a/device/vr/windows/compositor_base.cc
+++ b/device/vr/windows/compositor_base.cc
@@ -34,7 +34,8 @@
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       presentation_binding_(this),
       frame_data_binding_(this),
-      gamepad_provider_(this) {
+      gamepad_provider_(this),
+      overlay_binding_(this) {
   DCHECK(main_thread_task_runner_);
 }
 
@@ -129,6 +130,16 @@
   gamepad_provider_.Bind(std::move(request));
 }
 
+void XRCompositorCommon::RequestOverlay(
+    mojom::ImmersiveOverlayRequest request) {
+  overlay_binding_.Close();
+  overlay_binding_.Bind(std::move(request));
+
+  // WebXR is visible and overlay hidden by default until the overlay overrides
+  // this.
+  SetOverlayAndWebXRVisibility(false, true);
+}
+
 void XRCompositorCommon::UpdateLayerBounds(int16_t frame_id,
                                            const gfx::RectF& left_bounds,
                                            const gfx::RectF& right_bounds,
@@ -211,6 +222,7 @@
   // Kill outstanding overlays:
   overlay_visible_ = false;
   delayed_overlay_get_frame_data_callback_.Reset();
+  overlay_binding_.Close();
 
   texture_helper_.SetSourceAndOverlayVisible(false, false);
 
@@ -308,18 +320,18 @@
 
 void XRCompositorCommon::SubmitOverlayTexture(
     int16_t frame_id,
+    mojo::ScopedHandle texture_handle,
     const gfx::RectF& left_bounds,
     const gfx::RectF& right_bounds,
-    mojo::ScopedHandle texture_handle,
-    base::OnceCallback<void(bool)> present_succeeded) {
+    SubmitOverlayTextureCallback overlay_submit_callback) {
   DCHECK(overlay_visible_);
-  overlay_submit_succeeded_ = std::move(present_succeeded);
+  overlay_submit_callback_ = std::move(overlay_submit_callback);
   if (!pending_frame_) {
     // We may stop presenting while there is a pending SubmitOverlayTexture
     // outstanding.  If we get an overlay submit we weren't expecting, just
     // ignore it.
     DCHECK(!is_presenting_);
-    std::move(overlay_submit_succeeded_).Run(false);
+    std::move(overlay_submit_callback_).Run(false);
     return;
   }
 
@@ -337,7 +349,7 @@
         left_bounds, right_bounds);
     pending_frame_->overlay_submitted_ = true;
   } else {
-    std::move(overlay_submit_succeeded_).Run(false);
+    std::move(overlay_submit_callback_).Run(false);
   }
 
   // Regardless of success - try to composite what we have.
@@ -345,8 +357,8 @@
 #endif
 }
 
-void XRCompositorCommon::RequestOverlayPose(
-    XRFrameDataProvider::GetFrameDataCallback callback) {
+void XRCompositorCommon::RequestNextOverlayPose(
+    RequestNextOverlayPoseCallback callback) {
   // We will only request poses while the overlay is visible.
   DCHECK(overlay_visible_);
 
@@ -355,7 +367,7 @@
   if (pending_frame_ && pending_frame_->overlay_has_pose_) {
     DCHECK(!delayed_overlay_get_frame_data_callback_);
     delayed_overlay_get_frame_data_callback_ =
-        base::BindOnce(&XRCompositorCommon::RequestOverlayPose,
+        base::BindOnce(&XRCompositorCommon::RequestNextOverlayPose,
                        base::Unretained(this), std::move(callback));
     return;
   }
@@ -430,10 +442,10 @@
     submit_client_->OnSubmitFrameRendered();
   }
 
-  if (pending_frame_->overlay_submitted_ && overlay_submit_succeeded_) {
+  if (pending_frame_->overlay_submitted_ && overlay_submit_callback_) {
     // Tell the browser/overlay that we are done with its texture so it can be
     // reused.
-    std::move(overlay_submit_succeeded_).Run(copy_successful);
+    std::move(overlay_submit_callback_).Run(copy_successful);
   }
 
   ClearPendingFrame();
diff --git a/device/vr/windows/compositor_base.h b/device/vr/windows/compositor_base.h
index 3794d90d..29d8817ef 100644
--- a/device/vr/windows/compositor_base.h
+++ b/device/vr/windows/compositor_base.h
@@ -34,27 +34,12 @@
   virtual void OnLayerBoundsChanged();
 };
 
-// This will become a mojo interface
-class XROverlayCompositor {
- public:
-  virtual void SubmitOverlayTexture(
-      int16_t frame_id,
-      const gfx::RectF& left_bounds,
-      const gfx::RectF& right_bounds,
-      mojo::ScopedHandle texture_handle,
-      base::OnceCallback<void(bool)> present_succeeded) = 0;
-  virtual void RequestOverlayPose(
-      mojom::XRFrameDataProvider::GetFrameDataCallback callback) = 0;
-  virtual void SetOverlayAndWebXRVisibility(bool overlay_visible,
-                                            bool webxr_visible) = 0;
-};
-
 class XRCompositorCommon : public base::Thread,
                            public XRDeviceAbstraction,
                            public mojom::XRPresentationProvider,
                            public mojom::XRFrameDataProvider,
                            public mojom::IsolatedXRGamepadProvider,
-                           public XROverlayCompositor {
+                           public mojom::ImmersiveOverlay {
  public:
   using RequestSessionCallback =
       base::OnceCallback<void(bool result, mojom::XRSessionPtr)>;
@@ -73,6 +58,7 @@
       mojom::XRFrameDataPtr frame_data);
 
   void RequestGamepadProvider(mojom::IsolatedXRGamepadProviderRequest request);
+  void RequestOverlay(mojom::ImmersiveOverlayRequest request);
 
  protected:
 #if defined(OS_WIN)
@@ -117,15 +103,13 @@
                          const gfx::RectF& right_bounds,
                          const gfx::Size& source_size) final;
 
-  // XROverlayCompositor:
-  void SubmitOverlayTexture(
-      int16_t frame_id,
-      const gfx::RectF& left_bounds,
-      const gfx::RectF& right_bounds,
-      mojo::ScopedHandle texture_handle,
-      base::OnceCallback<void(bool)> present_succeeded) override;
-  void RequestOverlayPose(
-      XRFrameDataProvider::GetFrameDataCallback callback) override;
+  // ImmersiveOverlay:
+  void SubmitOverlayTexture(int16_t frame_id,
+                            mojo::ScopedHandle texture,
+                            const gfx::RectF& left_bounds,
+                            const gfx::RectF& right_bounds,
+                            SubmitOverlayTextureCallback callback) override;
+  void RequestNextOverlayPose(RequestNextOverlayPoseCallback callback) override;
   void SetOverlayAndWebXRVisibility(bool overlay_visible,
                                     bool webxr_visible) override;
 
@@ -154,12 +138,13 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
   mojom::XRPresentationClientPtr submit_client_;
-  base::OnceCallback<void(bool)> overlay_submit_succeeded_;
+  SubmitOverlayTextureCallback overlay_submit_callback_;
   base::OnceCallback<void()> on_presentation_ended_;
   mojom::IsolatedXRGamepadProvider::RequestUpdateCallback gamepad_callback_;
   mojo::Binding<mojom::XRPresentationProvider> presentation_binding_;
   mojo::Binding<mojom::XRFrameDataProvider> frame_data_binding_;
   mojo::Binding<mojom::IsolatedXRGamepadProvider> gamepad_provider_;
+  mojo::Binding<mojom::ImmersiveOverlay> overlay_binding_;
 
   DISALLOW_COPY_AND_ASSIGN(XRCompositorCommon);
 };
diff --git a/device/vr/windows/d3d11_texture_helper.cc b/device/vr/windows/d3d11_texture_helper.cc
index ae9b04d..f24e9be 100644
--- a/device/vr/windows/d3d11_texture_helper.cc
+++ b/device/vr/windows/d3d11_texture_helper.cc
@@ -78,6 +78,56 @@
   layer.submitted_this_frame_ = false;
 }
 
+bool D3D11TextureHelper::EnsureOverlayBlendState() {
+  if (!render_state_.overlay_blend_state_) {
+    D3D11_BLEND_DESC blenddesc = {};
+    blenddesc.RenderTarget[0].BlendEnable = true;
+    blenddesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+    blenddesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+    blenddesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+    blenddesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+    blenddesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+    blenddesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+    blenddesc.RenderTarget[0].RenderTargetWriteMask =
+        D3D11_COLOR_WRITE_ENABLE_ALL;
+    HRESULT hr = render_state_.d3d11_device_->CreateBlendState(
+        &blenddesc,
+        render_state_.overlay_blend_state_.ReleaseAndGetAddressOf());
+    if (FAILED(hr))
+      return false;
+  }
+
+  if (render_state_.overlay_blend_state_ !=
+      render_state_.current_blend_state_) {
+    render_state_.d3d11_device_context_->OMSetBlendState(
+        render_state_.overlay_blend_state_.Get(), 0, -1);
+    render_state_.current_blend_state_ = render_state_.overlay_blend_state_;
+  }
+  return true;
+}
+
+bool D3D11TextureHelper::EnsureContentBlendState() {
+  if (!render_state_.content_blend_state_) {
+    D3D11_BLEND_DESC blenddesc = {};
+    blenddesc.RenderTarget[0].BlendEnable = false;
+    blenddesc.RenderTarget[0].RenderTargetWriteMask =
+        D3D11_COLOR_WRITE_ENABLE_ALL;
+    HRESULT hr = render_state_.d3d11_device_->CreateBlendState(
+        &blenddesc,
+        render_state_.content_blend_state_.ReleaseAndGetAddressOf());
+    if (FAILED(hr))
+      return false;
+  }
+
+  if (render_state_.content_blend_state_ !=
+      render_state_.current_blend_state_) {
+    render_state_.d3d11_device_context_->OMSetBlendState(
+        render_state_.content_blend_state_.Get(), 0, -1);
+    render_state_.current_blend_state_ = render_state_.content_blend_state_;
+  }
+  return true;
+}
+
 bool D3D11TextureHelper::CompositeToBackBuffer() {
   if (!EnsureInitialized())
     return false;
@@ -130,9 +180,11 @@
 
   bool success = true;
   if (render_state_.source_.source_texture_)
-    success = success && CompositeLayer(render_state_.source_);
+    success = success && EnsureContentBlendState() &&
+              CompositeLayer(render_state_.source_);
   if (render_state_.overlay_.source_texture_)
-    success = success && CompositeLayer(render_state_.overlay_);
+    success = success && EnsureOverlayBlendState() &&
+              CompositeLayer(render_state_.overlay_);
 
   if (render_state_.source_.keyed_mutex_)
     render_state_.source_.keyed_mutex_->ReleaseSync(0);
diff --git a/device/vr/windows/d3d11_texture_helper.h b/device/vr/windows/d3d11_texture_helper.h
index bf2b607..fb16e388 100644
--- a/device/vr/windows/d3d11_texture_helper.h
+++ b/device/vr/windows/d3d11_texture_helper.h
@@ -63,6 +63,8 @@
     bool submitted_this_frame_ = false;
   };
 
+  bool EnsureOverlayBlendState();
+  bool EnsureContentBlendState();
   bool EnsureRenderTargetView();
   bool EnsureShaders();
   bool EnsureInputLayout();
@@ -89,6 +91,10 @@
     Microsoft::WRL::ComPtr<ID3D11Buffer> vertex_buffer_;
     Microsoft::WRL::ComPtr<ID3D11Texture2D> target_texture_;
 
+    Microsoft::WRL::ComPtr<ID3D11BlendState> content_blend_state_;
+    Microsoft::WRL::ComPtr<ID3D11BlendState> overlay_blend_state_;
+    Microsoft::WRL::ComPtr<ID3D11BlendState> current_blend_state_;
+
     LayerData source_;
     LayerData overlay_;
   };
diff --git a/device/vr/windows/flip_pixel_shader.h b/device/vr/windows/flip_pixel_shader.h
index ba5ad0b..508aede 100644
--- a/device/vr/windows/flip_pixel_shader.h
+++ b/device/vr/windows/flip_pixel_shader.h
@@ -3,6 +3,8 @@
 // found in the LICENSE file.
 
 // DO NOT MODIFY.  Use generate_shaders.bat to modify, then re-add this warning.
+#ifndef DEVICE_VR_WINDOWS_FLIP_PIXEL_SHADER_H_
+#define DEVICE_VR_WINDOWS_FLIP_PIXEL_SHADER_H_
 
 #if 0
 //
@@ -22,8 +24,8 @@
 //
 // Name                 Index   Mask Register SysValue  Format   Used
 // -------------------- ----- ------ -------- -------- ------- ------
-// SV_POSITION              0   xyzw        0      POS   float       
-// TEXCOORD                 0   xy          1     NONE   float   xy  
+// SV_POSITION              0   xyzw        0      POS   float
+// TEXCOORD                 0   xy          1     NONE   float   xy
 //
 //
 // Output signature:
@@ -43,79 +45,70 @@
 // Level9 shader bytecode:
 //
     ps_2_x
-    def c0, 1, 0, 0, 0
     dcl t0.xy
     dcl_2d s0
     texld r0, t0, s0
-    mad r0, r0.xyzx, c0.xxxy, c0.yyyx
     mov oC0, r0
 
-// approximately 3 instruction slots used (1 texture, 2 arithmetic)
+// approximately 2 instruction slots used (1 texture, 1 arithmetic)
 ps_4_0
 dcl_sampler s0, mode_default
 dcl_resource_texture2d (float,float,float,float) t0
 dcl_input_ps linear v1.xy
 dcl_output o0.xyzw
-dcl_temps 1
-sample r0.xyzw, v1.xyxx, t0.xyzw, s0
-mov o0.xyz, r0.xyzx
-mov o0.w, l(1.000000)
+sample o0.xyzw, v1.xyxx, t0.xyzw, s0
 ret 
-// Approximately 4 instruction slots used
+// Approximately 2 instruction slots used
 #endif
 
 const BYTE g_flip_pixel[] = {
-    68,  88,  66,  67,  122, 236, 34,  82,  47,  62,  55,  18,  155, 66,  128,
-    241, 136, 87,  63,  239, 1,   0,   0,   0,   32,  3,   0,   0,   6,   0,
-    0,   0,   56,  0,   0,   0,   208, 0,   0,   0,   108, 1,   0,   0,   232,
-    1,   0,   0,   148, 2,   0,   0,   236, 2,   0,   0,   65,  111, 110, 57,
-    144, 0,   0,   0,   144, 0,   0,   0,   0,   2,   255, 255, 104, 0,   0,
+    68,  88,  66,  67,  192, 36,  143, 138, 147, 91,  77,  61,  65,  22,  238,
+    11,  132, 7,   50,  248, 1,   0,   0,   0,   196, 2,   0,   0,   6,   0,
+    0,   0,   56,  0,   0,   0,   164, 0,   0,   0,   16,  1,   0,   0,   140,
+    1,   0,   0,   56,  2,   0,   0,   144, 2,   0,   0,   65,  111, 110, 57,
+    100, 0,   0,   0,   100, 0,   0,   0,   0,   2,   255, 255, 60,  0,   0,
     0,   40,  0,   0,   0,   0,   0,   40,  0,   0,   0,   40,  0,   0,   0,
     40,  0,   1,   0,   36,  0,   0,   0,   40,  0,   0,   0,   0,   0,   1,
-    2,   255, 255, 81,  0,   0,   5,   0,   0,   15,  160, 0,   0,   128, 63,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   31,  0,   0,
-    2,   0,   0,   0,   128, 0,   0,   3,   176, 31,  0,   0,   2,   0,   0,
-    0,   144, 0,   8,   15,  160, 66,  0,   0,   3,   0,   0,   15,  128, 0,
-    0,   228, 176, 0,   8,   228, 160, 4,   0,   0,   4,   0,   0,   15,  128,
-    0,   0,   36,  128, 0,   0,   64,  160, 0,   0,   21,  160, 1,   0,   0,
-    2,   0,   8,   15,  128, 0,   0,   228, 128, 255, 255, 0,   0,   83,  72,
-    68,  82,  148, 0,   0,   0,   64,  0,   0,   0,   37,  0,   0,   0,   90,
-    0,   0,   3,   0,   96,  16,  0,   0,   0,   0,   0,   88,  24,  0,   4,
-    0,   112, 16,  0,   0,   0,   0,   0,   85,  85,  0,   0,   98,  16,  0,
-    3,   50,  16,  16,  0,   1,   0,   0,   0,   101, 0,   0,   3,   242, 32,
-    16,  0,   0,   0,   0,   0,   104, 0,   0,   2,   1,   0,   0,   0,   69,
-    0,   0,   9,   242, 0,   16,  0,   0,   0,   0,   0,   70,  16,  16,  0,
-    1,   0,   0,   0,   70,  126, 16,  0,   0,   0,   0,   0,   0,   96,  16,
-    0,   0,   0,   0,   0,   54,  0,   0,   5,   114, 32,  16,  0,   0,   0,
-    0,   0,   70,  2,   16,  0,   0,   0,   0,   0,   54,  0,   0,   5,   130,
-    32,  16,  0,   0,   0,   0,   0,   1,   64,  0,   0,   0,   0,   128, 63,
-    62,  0,   0,   1,   83,  84,  65,  84,  116, 0,   0,   0,   4,   0,   0,
-    0,   1,   0,   0,   0,   0,   0,   0,   0,   2,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    2,   255, 255, 31,  0,   0,   2,   0,   0,   0,   128, 0,   0,   3,   176,
+    31,  0,   0,   2,   0,   0,   0,   144, 0,   8,   15,  160, 66,  0,   0,
+    3,   0,   0,   15,  128, 0,   0,   228, 176, 0,   8,   228, 160, 1,   0,
+    0,   2,   0,   8,   15,  128, 0,   0,   228, 128, 255, 255, 0,   0,   83,
+    72,  68,  82,  100, 0,   0,   0,   64,  0,   0,   0,   25,  0,   0,   0,
+    90,  0,   0,   3,   0,   96,  16,  0,   0,   0,   0,   0,   88,  24,  0,
+    4,   0,   112, 16,  0,   0,   0,   0,   0,   85,  85,  0,   0,   98,  16,
+    0,   3,   50,  16,  16,  0,   1,   0,   0,   0,   101, 0,   0,   3,   242,
+    32,  16,  0,   0,   0,   0,   0,   69,  0,   0,   9,   242, 32,  16,  0,
+    0,   0,   0,   0,   70,  16,  16,  0,   1,   0,   0,   0,   70,  126, 16,
+    0,   0,   0,   0,   0,   0,   96,  16,  0,   0,   0,   0,   0,   62,  0,
+    0,   1,   83,  84,  65,  84,  116, 0,   0,   0,   2,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   2,   0,   0,   0,   0,   0,   0,   0,
     0,   0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   2,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   0,
     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   82,  68,  69,  70,  164, 0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   2,   0,   0,   0,   28,  0,
-    0,   0,   0,   4,   255, 255, 0,   1,   0,   0,   114, 0,   0,   0,   92,
-    0,   0,   0,   3,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,
-    0,   103, 0,   0,   0,   2,   0,   0,   0,   5,   0,   0,   0,   4,   0,
-    0,   0,   255, 255, 255, 255, 0,   0,   0,   0,   1,   0,   0,   0,   12,
-    0,   0,   0,   109, 121, 95,  115, 97,  109, 112, 108, 101, 114, 0,   109,
-    121, 95,  116, 101, 120, 116, 117, 114, 101, 0,   77,  105, 99,  114, 111,
-    115, 111, 102, 116, 32,  40,  82,  41,  32,  72,  76,  83,  76,  32,  83,
-    104, 97,  100, 101, 114, 32,  67,  111, 109, 112, 105, 108, 101, 114, 32,
-    54,  46,  51,  46,  57,  54,  48,  48,  46,  49,  54,  51,  56,  52,  0,
-    73,  83,  71,  78,  80,  0,   0,   0,   2,   0,   0,   0,   8,   0,   0,
-    0,   56,  0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   3,   0,
-    0,   0,   0,   0,   0,   0,   15,  0,   0,   0,   68,  0,   0,   0,   0,
-    0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,   1,   0,   0,   0,
-    3,   3,   0,   0,   83,  86,  95,  80,  79,  83,  73,  84,  73,  79,  78,
-    0,   84,  69,  88,  67,  79,  79,  82,  68,  0,   171, 171, 171, 79,  83,
-    71,  78,  44,  0,   0,   0,   1,   0,   0,   0,   8,   0,   0,   0,   32,
-    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,
-    0,   0,   0,   0,   15,  0,   0,   0,   83,  86,  95,  84,  65,  82,  71,
-    69,  84,  0,   171, 171};
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   82,  68,  69,  70,  164, 0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   2,   0,   0,   0,   28,  0,   0,   0,
+    0,   4,   255, 255, 0,   1,   0,   0,   114, 0,   0,   0,   92,  0,   0,
+    0,   3,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   0,   0,   0,   0,   103,
+    0,   0,   0,   2,   0,   0,   0,   5,   0,   0,   0,   4,   0,   0,   0,
+    255, 255, 255, 255, 0,   0,   0,   0,   1,   0,   0,   0,   12,  0,   0,
+    0,   109, 121, 95,  115, 97,  109, 112, 108, 101, 114, 0,   109, 121, 95,
+    116, 101, 120, 116, 117, 114, 101, 0,   77,  105, 99,  114, 111, 115, 111,
+    102, 116, 32,  40,  82,  41,  32,  72,  76,  83,  76,  32,  83,  104, 97,
+    100, 101, 114, 32,  67,  111, 109, 112, 105, 108, 101, 114, 32,  54,  46,
+    51,  46,  57,  54,  48,  48,  46,  49,  54,  51,  56,  52,  0,   73,  83,
+    71,  78,  80,  0,   0,   0,   2,   0,   0,   0,   8,   0,   0,   0,   56,
+    0,   0,   0,   0,   0,   0,   0,   1,   0,   0,   0,   3,   0,   0,   0,
+    0,   0,   0,   0,   15,  0,   0,   0,   68,  0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   3,   0,   0,   0,   1,   0,   0,   0,   3,   3,
+    0,   0,   83,  86,  95,  80,  79,  83,  73,  84,  73,  79,  78,  0,   84,
+    69,  88,  67,  79,  79,  82,  68,  0,   171, 171, 171, 79,  83,  71,  78,
+    44,  0,   0,   0,   1,   0,   0,   0,   8,   0,   0,   0,   32,  0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,   0,   0,
+    0,   0,   15,  0,   0,   0,   83,  86,  95,  84,  65,  82,  71,  69,  84,
+    0,   171, 171};
+
+#endif  // DEVICE_VR_WINDOWS_FLIP_PIXEL_SHADER_H_
diff --git a/device/vr/windows/flip_pixel_shader.hlsl b/device/vr/windows/flip_pixel_shader.hlsl
index f2cd885..b030bc4 100644
--- a/device/vr/windows/flip_pixel_shader.hlsl
+++ b/device/vr/windows/flip_pixel_shader.hlsl
@@ -18,5 +18,5 @@
 float4 flip_pixel(PixelShaderInput input) : SV_TARGET
 {
   float2 texture_coords = float2(input.tex.x, input.tex.y);
-  return float4(my_texture.Sample(my_sampler, texture_coords).rgb, 1.0f);
+  return my_texture.Sample(my_sampler, texture_coords).rgba;
 }
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index 213c0a7..b8c2091 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -7,7 +7,6 @@
 #include "base/logging.h"
 #include "extensions/browser/api/device_permissions_prompt.h"
 #include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h"
-#include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
 #include "extensions/browser/guest_view/extensions_guest_view_manager_delegate.h"
 #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h"
 #include "extensions/browser/guest_view/web_view/web_view_permission_helper_delegate.h"
@@ -48,6 +47,11 @@
   return false;
 }
 
+void ExtensionsAPIClient::NotifyWebRequestWithheld(
+    int render_process_id,
+    int render_frame_id,
+    const ExtensionId& extension_id) {}
+
 AppViewGuestDelegate* ExtensionsAPIClient::CreateAppViewGuestDelegate() const {
   return NULL;
 }
@@ -81,11 +85,6 @@
   return new WebViewPermissionHelperDelegate(web_view_permission_helper);
 }
 
-std::unique_ptr<WebRequestEventRouterDelegate>
-ExtensionsAPIClient::CreateWebRequestEventRouterDelegate() const {
-  return nullptr;
-}
-
 scoped_refptr<ContentRulesRegistry>
 ExtensionsAPIClient::CreateContentRulesRegistry(
     content::BrowserContext* browser_context,
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index 32ddf2b..a818412a 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -15,6 +15,7 @@
 #include "extensions/browser/api/declarative_content/content_rules_registry.h"
 #include "extensions/browser/api/storage/settings_namespace.h"
 #include "extensions/common/api/clipboard.h"
+#include "extensions/common/extension_id.h"
 
 class GURL;
 
@@ -54,7 +55,6 @@
 class ValueStoreCache;
 class ValueStoreFactory;
 class VirtualKeyboardDelegate;
-class WebRequestEventRouterDelegate;
 struct WebRequestInfo;
 class WebViewGuest;
 class WebViewGuestDelegate;
@@ -100,6 +100,12 @@
   virtual bool ShouldHideBrowserNetworkRequest(
       const WebRequestInfo& request) const;
 
+  // Notifies that an extension failed to act on a network request because the
+  // access to request was withheld.
+  virtual void NotifyWebRequestWithheld(int render_process_id,
+                                        int render_frame_id,
+                                        const ExtensionId& extension_id);
+
   // Creates the AppViewGuestDelegate.
   virtual AppViewGuestDelegate* CreateAppViewGuestDelegate() const;
 
@@ -127,10 +133,6 @@
   CreateWebViewPermissionHelperDelegate(
       WebViewPermissionHelper* web_view_permission_helper) const;
 
-  // Creates a delegate for WebRequestEventRouter.
-  virtual std::unique_ptr<WebRequestEventRouterDelegate>
-  CreateWebRequestEventRouterDelegate() const;
-
   // TODO(wjmaclean): Remove this when (if) ContentRulesRegistry code moves
   // to extensions/browser/api.
   virtual scoped_refptr<ContentRulesRegistry> CreateContentRulesRegistry(
diff --git a/extensions/browser/api/web_request/BUILD.gn b/extensions/browser/api/web_request/BUILD.gn
index b98dd3e..8b67cc3 100644
--- a/extensions/browser/api/web_request/BUILD.gn
+++ b/extensions/browser/api/web_request/BUILD.gn
@@ -21,7 +21,6 @@
     "web_request_api_helpers.h",
     "web_request_event_details.cc",
     "web_request_event_details.h",
-    "web_request_event_router_delegate.h",
     "web_request_info.cc",
     "web_request_info.h",
     "web_request_permissions.cc",
diff --git a/extensions/browser/api/web_request/web_request_api.cc b/extensions/browser/api/web_request/web_request_api.cc
index 327d03c..5202159 100644
--- a/extensions/browser/api/web_request/web_request_api.cc
+++ b/extensions/browser/api/web_request/web_request_api.cc
@@ -50,7 +50,6 @@
 #include "extensions/browser/api/web_request/web_request_api_constants.h"
 #include "extensions/browser/api/web_request/web_request_api_helpers.h"
 #include "extensions/browser/api/web_request/web_request_event_details.h"
-#include "extensions/browser/api/web_request/web_request_event_router_delegate.h"
 #include "extensions/browser/api/web_request/web_request_info.h"
 #include "extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h"
 #include "extensions/browser/api/web_request/web_request_proxying_websocket.h"
@@ -897,9 +896,6 @@
 
 ExtensionWebRequestEventRouter::ExtensionWebRequestEventRouter()
     : request_time_tracker_(new ExtensionWebRequestTimeTracker) {
-  DCHECK(ExtensionsAPIClient::Get());
-  web_request_event_router_delegate_ =
-      ExtensionsAPIClient::Get()->CreateWebRequestEventRouterDelegate();
 }
 
 void ExtensionWebRequestEventRouter::RegisterRulesRegistry(
@@ -1743,9 +1739,9 @@
               request->initiator);
 
       if (access != PermissionsData::PageAccess::kAllowed) {
-        if (access == PermissionsData::PageAccess::kWithheld &&
-            web_request_event_router_delegate_) {
-          web_request_event_router_delegate_->NotifyWebRequestWithheld(
+        if (access == PermissionsData::PageAccess::kWithheld) {
+          DCHECK(ExtensionsAPIClient::Get());
+          ExtensionsAPIClient::Get()->NotifyWebRequestWithheld(
               request->render_process_id, request->frame_id,
               listener->id.extension_id);
         }
diff --git a/extensions/browser/api/web_request/web_request_api.h b/extensions/browser/api/web_request/web_request_api.h
index 03d6ad3a..0c96184e 100644
--- a/extensions/browser/api/web_request/web_request_api.h
+++ b/extensions/browser/api/web_request/web_request_api.h
@@ -64,7 +64,6 @@
 
 class InfoMap;
 class WebRequestEventDetails;
-class WebRequestEventRouterDelegate;
 struct WebRequestInfo;
 class WebRequestRulesRegistry;
 
@@ -705,9 +704,6 @@
   std::map<RulesRegistryKey,
       scoped_refptr<extensions::WebRequestRulesRegistry> > rules_registries_;
 
-  std::unique_ptr<extensions::WebRequestEventRouterDelegate>
-      web_request_event_router_delegate_;
-
   DISALLOW_COPY_AND_ASSIGN(ExtensionWebRequestEventRouter);
 };
 
diff --git a/extensions/browser/api/web_request/web_request_event_router_delegate.h b/extensions/browser/api/web_request/web_request_event_router_delegate.h
deleted file mode 100644
index 0ae3e08d..0000000
--- a/extensions/browser/api/web_request/web_request_event_router_delegate.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_BROWSER_API_WEB_REQUEST_WEB_REQUEST_EVENT_ROUTER_DELEGATE_H_
-#define EXTENSIONS_BROWSER_API_WEB_REQUEST_WEB_REQUEST_EVENT_ROUTER_DELEGATE_H_
-
-#include <string>
-
-namespace extensions {
-
-// A delegate class of WebRequestApi that are not a part of chrome.
-class WebRequestEventRouterDelegate {
- public:
-  virtual ~WebRequestEventRouterDelegate() {}
-
-  // Notifies that a webRequest event that normally would be forwarded to a
-  // listener was instead blocked because of withheld permissions.
-  virtual void NotifyWebRequestWithheld(int render_process_id,
-                                        int render_frame_id,
-                                        const std::string& extension_id) = 0;
-};
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_BROWSER_API_WEB_REQUEST_WEB_REQUEST_EVENT_ROUTER_DELEGATE_H_
diff --git a/extensions/browser/extension_function.h b/extensions/browser/extension_function.h
index 2cf935ba..2201b0a 100644
--- a/extensions/browser/extension_function.h
+++ b/extensions/browser/extension_function.h
@@ -347,7 +347,7 @@
   // Error. chrome.runtime.lastError.message will be set to |error|.
   ResponseValue Error(const std::string& error);
   // Error with formatting. Args are processed using
-  // ErrorUtils::FormatErrorMessage, that is, each occurence of * is replaced
+  // ErrorUtils::FormatErrorMessage, that is, each occurrence of * is replaced
   // by the corresponding |s*|:
   // Error("Error in *: *", "foo", "bar") <--> Error("Error in foo: bar").
   ResponseValue Error(const std::string& format, const std::string& s1);
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 315148f6..c311250e 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -10,22 +10,27 @@
 
 config("gpu_implementation") {
   defines = [ "GPU_IMPLEMENTATION" ]
+  configs = [ "//build/config/compiler:wexit_time_destructors" ]
 }
 
 config("gpu_gles2_implementation") {
   defines = [ "GPU_GLES2_IMPLEMENTATION" ]
+  configs = [ "//build/config/compiler:wexit_time_destructors" ]
 }
 
 config("gpu_util_implementation") {
   defines = [ "GPU_UTIL_IMPLEMENTATION" ]
+  configs = [ "//build/config/compiler:wexit_time_destructors" ]
 }
 
 config("raster_implementation") {
   defines = [ "RASTER_IMPLEMENTATION" ]
+  configs = [ "//build/config/compiler:wexit_time_destructors" ]
 }
 
 config("webgpu_implementation") {
   defines = [ "WEBGPU_IMPLEMENTATION" ]
+  configs = [ "//build/config/compiler:wexit_time_destructors" ]
 }
 
 component("gpu") {
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 6a18c79..65f83c6 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -6315,15 +6315,6 @@
 bool CreateImageValidInternalFormat(GLenum internalformat,
                                     const Capabilities& capabilities) {
   switch (internalformat) {
-    case GL_ATC_RGB_AMD:
-    case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
-      return capabilities.texture_format_atc;
-    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-      return capabilities.texture_format_dxt1;
-    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-      return capabilities.texture_format_dxt5;
-    case GL_ETC1_RGB8_OES:
-      return capabilities.texture_format_etc1;
     case GL_R16_EXT:
       return capabilities.texture_norm16;
     case GL_RGB10_A2_EXT:
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc
index e7e42cf6..3891067c 100644
--- a/gpu/command_buffer/client/raster_implementation.cc
+++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -903,15 +903,6 @@
 bool CreateImageValidInternalFormat(GLenum internalformat,
                                     const Capabilities& capabilities) {
   switch (internalformat) {
-    case GL_ATC_RGB_AMD:
-    case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
-      return capabilities.texture_format_atc;
-    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-      return capabilities.texture_format_dxt1;
-    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-      return capabilities.texture_format_dxt5;
-    case GL_ETC1_RGB8_OES:
-      return capabilities.texture_format_etc1;
     case GL_R16_EXT:
       return capabilities.texture_norm16;
     case GL_RGB10_A2_EXT:
diff --git a/gpu/command_buffer/client/webgpu_implementation.h b/gpu/command_buffer/client/webgpu_implementation.h
index 3363ea0..87b22403 100644
--- a/gpu/command_buffer/client/webgpu_implementation.h
+++ b/gpu/command_buffer/client/webgpu_implementation.h
@@ -25,10 +25,7 @@
 #include "gpu/command_buffer/client/webgpu_implementation_autogen.h"
 
  private:
-  const std::string& GetLogPrefix() const {
-    static const std::string prefix = "webgpu";
-    return prefix;
-  }
+  const char* GetLogPrefix() const { return "webgpu"; }
 
   WebGPUCmdHelper* helper_;
   LogSettings log_settings_;
diff --git a/gpu/command_buffer/common/buffer.cc b/gpu/command_buffer/common/buffer.cc
index 639a220..47092ad3e 100644
--- a/gpu/command_buffer/common/buffer.cc
+++ b/gpu/command_buffer/common/buffer.cc
@@ -9,6 +9,7 @@
 
 #include "base/format_macros.h"
 #include "base/logging.h"
+#include "base/no_destructor.h"
 #include "base/numerics/safe_math.h"
 #include "base/strings/stringprintf.h"
 
@@ -16,8 +17,9 @@
 
 const base::UnsafeSharedMemoryRegion& BufferBacking::shared_memory_region()
     const {
-  static const base::UnsafeSharedMemoryRegion kInvalidRegion;
-  return kInvalidRegion;
+  static const base::NoDestructor<base::UnsafeSharedMemoryRegion>
+      kInvalidRegion;
+  return *kInvalidRegion;
 }
 
 base::UnguessableToken BufferBacking::GetGUID() const {
diff --git a/gpu/command_buffer/common/gpu_memory_buffer_support.cc b/gpu/command_buffer/common/gpu_memory_buffer_support.cc
index 918d521..66368962 100644
--- a/gpu/command_buffer/common/gpu_memory_buffer_support.cc
+++ b/gpu/command_buffer/common/gpu_memory_buffer_support.cc
@@ -29,16 +29,6 @@
       return gfx::BufferFormat::RGBA_8888;
     case GL_BGRA_EXT:
       return gfx::BufferFormat::BGRA_8888;
-    case GL_ATC_RGB_AMD:
-      return gfx::BufferFormat::ATC;
-    case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
-      return gfx::BufferFormat::ATCIA;
-    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-      return gfx::BufferFormat::DXT1;
-    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-      return gfx::BufferFormat::DXT5;
-    case GL_ETC1_RGB8_OES:
-      return gfx::BufferFormat::ETC1;
     case GL_RGB_YCRCB_420_CHROMIUM:
       return gfx::BufferFormat::YVU_420;
     case GL_RGB_YCBCR_420V_CHROMIUM:
@@ -57,13 +47,8 @@
     unsigned internalformat,
     gfx::BufferFormat format) {
   switch (format) {
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
     case gfx::BufferFormat::BGRA_8888:
     case gfx::BufferFormat::BGRX_8888:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::R_8:
     case gfx::BufferFormat::R_16:
     case gfx::BufferFormat::RG_88:
@@ -91,18 +76,9 @@
     gfx::BufferFormat format,
     const gpu::Capabilities& capabilities) {
   switch (format) {
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-      return capabilities.texture_format_atc;
     case gfx::BufferFormat::BGRA_8888:
     case gfx::BufferFormat::BGRX_8888:
       return capabilities.texture_format_bgra8888;
-    case gfx::BufferFormat::DXT1:
-      return capabilities.texture_format_dxt1;
-    case gfx::BufferFormat::DXT5:
-      return capabilities.texture_format_dxt5;
-    case gfx::BufferFormat::ETC1:
-      return capabilities.texture_format_etc1;
     case gfx::BufferFormat::R_16:
       return capabilities.texture_norm16;
     case gfx::BufferFormat::R_8:
@@ -133,14 +109,6 @@
 bool IsImageSizeValidForGpuMemoryBufferFormat(const gfx::Size& size,
                                               gfx::BufferFormat format) {
   switch (format) {
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
-      // Compressed images must have a width and height that's evenly divisible
-      // by the block size.
-      return size.width() % 4 == 0 && size.height() % 4 == 0;
     case gfx::BufferFormat::R_8:
     case gfx::BufferFormat::R_16:
     case gfx::BufferFormat::RG_88:
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 51b1bcb..f8f2d72c 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -226,6 +226,10 @@
   feature_flags_.chromium_raster_transport =
       gpu_feature_info.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] ==
       gpu::kGpuFeatureStatusEnabled;
+  feature_flags_.android_surface_control =
+      gpu_feature_info
+          .status_values[GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] ==
+      gpu::kGpuFeatureStatusEnabled;
 }
 
 void FeatureInfo::InitializeBasicState(const base::CommandLine* command_line) {
diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h
index c899985..ee9f949 100644
--- a/gpu/command_buffer/service/feature_info.h
+++ b/gpu/command_buffer/service/feature_info.h
@@ -132,6 +132,7 @@
     bool mesa_framebuffer_flip_y = false;
     bool angle_multiview = false;
     bool khr_parallel_shader_compile = false;
+    bool android_surface_control = false;
   };
 
   FeatureInfo();
diff --git a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
index 90feca4..24660c6 100644
--- a/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
+++ b/gpu/command_buffer/tests/gl_gpu_memory_buffer_unittest.cc
@@ -179,13 +179,8 @@
             ((pixel[0] << 2) | (pixel[0] >> 6));         // R
       }
       return;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
     case gfx::BufferFormat::BGRX_8888:
     case gfx::BufferFormat::BGRX_1010102:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::R_16:
     case gfx::BufferFormat::RG_88:
     case gfx::BufferFormat::UYVY_422:
@@ -216,13 +211,8 @@
       return GL_BGRA_EXT;
     case gfx::BufferFormat::RGBA_F16:
       return GL_RGBA;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
     case gfx::BufferFormat::BGRX_8888:
     case gfx::BufferFormat::BGRX_1010102:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::RGBX_8888:
     case gfx::BufferFormat::UYVY_422:
     case gfx::BufferFormat::YVU_420:
diff --git a/gpu/config/gpu_blacklist.cc b/gpu/config/gpu_blacklist.cc
index 553d1c1..e7e24c8d 100644
--- a/gpu/config/gpu_blacklist.cc
+++ b/gpu/config/gpu_blacklist.cc
@@ -45,6 +45,9 @@
                             GPU_FEATURE_TYPE_PROTECTED_VIDEO_DECODE);
   list->AddSupportedFeature("oop_rasterization",
                             GPU_FEATURE_TYPE_OOP_RASTERIZATION);
+  list->AddSupportedFeature("android_surface_control",
+                            GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL);
+
   return list;
 }
 
diff --git a/gpu/config/gpu_feature_type.h b/gpu/config/gpu_feature_type.h
index 3587f075..a9684b99 100644
--- a/gpu/config/gpu_feature_type.h
+++ b/gpu/config/gpu_feature_type.h
@@ -22,6 +22,7 @@
   GPU_FEATURE_TYPE_ACCELERATED_WEBGL2,
   GPU_FEATURE_TYPE_PROTECTED_VIDEO_DECODE,
   GPU_FEATURE_TYPE_OOP_RASTERIZATION,
+  GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL,
   NUMBER_OF_GPU_FEATURE_TYPES
 };
 
diff --git a/gpu/config/gpu_finch_features.cc b/gpu/config/gpu_finch_features.cc
index 8ce538d..4ba4828 100644
--- a/gpu/config/gpu_finch_features.cc
+++ b/gpu/config/gpu_finch_features.cc
@@ -37,6 +37,12 @@
 // Use android AImageReader when playing videos with MediaPlayer.
 const base::Feature kAImageReaderMediaPlayer{"AImageReaderMediaPlayer",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Use android SurfaceControl API for managing display compositor's buffer queue
+// and using overlays on Android.
+// Note that the feature only works with VizDisplayCompositor enabled.
+const base::Feature kAndroidSurfaceControl{"AndroidSurfaceControl",
+                                           base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
 // Overrides preferred overlay format to NV12 instead of YUY2.
diff --git a/gpu/config/gpu_finch_features.h b/gpu/config/gpu_finch_features.h
index c4e6799e..8d17687 100644
--- a/gpu/config/gpu_finch_features.h
+++ b/gpu/config/gpu_finch_features.h
@@ -26,6 +26,7 @@
 
 #if defined(OS_ANDROID)
 GPU_EXPORT extern const base::Feature kAImageReaderMediaPlayer;
+GPU_EXPORT extern const base::Feature kAndroidSurfaceControl;
 #endif  // defined(OS_ANDROID)
 
 GPU_EXPORT extern const base::Feature kDirectCompositionPreferNV12Overlays;
diff --git a/gpu/config/gpu_preferences.h b/gpu/config/gpu_preferences.h
index 7ca2142..8b7286c 100644
--- a/gpu/config/gpu_preferences.h
+++ b/gpu/config/gpu_preferences.h
@@ -162,6 +162,9 @@
   // uses the defaults, which are encoded in the GPU process's code.
   uint32_t max_active_webgl_contexts = 0;
 
+  // Enables the use of SurfaceControl for overlays on Android.
+  bool enable_android_surface_control = false;
+
   // ===================================
   // Settings from //ui/gl/gl_switches.h
 
diff --git a/gpu/config/gpu_switches.h b/gpu/config/gpu_switches.h
index 5017f5f2..fa533cf 100644
--- a/gpu/config/gpu_switches.h
+++ b/gpu/config/gpu_switches.h
@@ -22,6 +22,7 @@
 GPU_EXPORT extern const char kWebglMSAASampleCount[];
 GPU_EXPORT extern const char kDisableGpuProcessForDX12VulkanInfoCollection[];
 GPU_EXPORT extern const char kEnableUnsafeWebGPU[];
+
 }  // namespace switches
 
 #endif  // GPU_CONFIG_GPU_SWITCHES_H_
diff --git a/gpu/config/gpu_util.cc b/gpu/config/gpu_util.cc
index 9468f779..522bd45 100644
--- a/gpu/config/gpu_util.cc
+++ b/gpu/config/gpu_util.cc
@@ -30,6 +30,7 @@
 #if defined(OS_ANDROID)
 #include "base/no_destructor.h"
 #include "base/synchronization/lock.h"
+#include "ui/gl/android/android_surface_composer_compat.h"
 #include "ui/gl/init/gl_factory.h"
 #endif  // OS_ANDROID
 
@@ -37,6 +38,25 @@
 
 namespace {
 
+GpuFeatureStatus GetAndroidSurfaceControlFeatureStatus(
+    const std::set<int>& blacklisted_features,
+    const GpuPreferences& gpu_preferences) {
+#if !defined(OS_ANDROID)
+  return kGpuFeatureStatusDisabled;
+#else
+  if (blacklisted_features.count(GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL))
+    return kGpuFeatureStatusBlacklisted;
+
+  if (!gpu_preferences.enable_android_surface_control)
+    return kGpuFeatureStatusDisabled;
+
+  if (!gl::SurfaceComposer::IsSupported())
+    return kGpuFeatureStatusDisabled;
+
+  return kGpuFeatureStatusEnabled;
+#endif
+}
+
 GpuFeatureStatus GetGpuRasterizationFeatureStatus(
     const std::set<int>& blacklisted_features,
     const base::CommandLine& command_line) {
@@ -250,6 +270,8 @@
       kGpuFeatureStatusDisabled;
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
       kGpuFeatureStatusDisabled;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] =
+      kGpuFeatureStatusDisabled;
 #if DCHECK_IS_ON()
   for (int ii = 0; ii < NUMBER_OF_GPU_FEATURE_TYPES; ++ii) {
     DCHECK_NE(kGpuFeatureStatusUndefined, gpu_feature_info.status_values[ii]);
@@ -282,6 +304,8 @@
       kGpuFeatureStatusDisabled;
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
       kGpuFeatureStatusDisabled;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] =
+      kGpuFeatureStatusDisabled;
 #if DCHECK_IS_ON()
   for (int ii = 0; ii < NUMBER_OF_GPU_FEATURE_TYPES; ++ii) {
     DCHECK_NE(kGpuFeatureStatusUndefined, gpu_feature_info.status_values[ii]);
@@ -314,6 +338,8 @@
       kGpuFeatureStatusDisabled;
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
       kGpuFeatureStatusDisabled;
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] =
+      kGpuFeatureStatusDisabled;
 #if DCHECK_IS_ON()
   for (int ii = 0; ii < NUMBER_OF_GPU_FEATURE_TYPES; ++ii) {
     DCHECK_NE(kGpuFeatureStatusUndefined, gpu_feature_info.status_values[ii]);
@@ -386,6 +412,9 @@
   gpu_feature_info.status_values[GPU_FEATURE_TYPE_OOP_RASTERIZATION] =
       GetOopRasterizationFeatureStatus(blacklisted_features, *command_line,
                                        gpu_preferences, gpu_info);
+  gpu_feature_info.status_values[GPU_FEATURE_TYPE_ANDROID_SURFACE_CONTROL] =
+      GetAndroidSurfaceControlFeatureStatus(blacklisted_features,
+                                            gpu_preferences);
 #if DCHECK_IS_ON()
   for (int ii = 0; ii < NUMBER_OF_GPU_FEATURE_TYPES; ++ii) {
     DCHECK_NE(kGpuFeatureStatusUndefined, gpu_feature_info.status_values[ii]);
diff --git a/gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.cc b/gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.cc
index 1769a4a..cba3a39 100644
--- a/gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.cc
+++ b/gpu/ipc/common/gpu_memory_buffer_impl_shared_memory.cc
@@ -135,14 +135,6 @@
     const gfx::Size& size,
     gfx::BufferFormat format) {
   switch (format) {
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
-      // Compressed images must have a width and height that's evenly divisible
-      // by the block size.
-      return size.width() % 4 == 0 && size.height() % 4 == 0;
     case gfx::BufferFormat::R_8:
     case gfx::BufferFormat::R_16:
     case gfx::BufferFormat::RG_88:
diff --git a/gpu/ipc/common/gpu_preferences.mojom b/gpu/ipc/common/gpu_preferences.mojom
index 05e89ef..17ae7d9 100644
--- a/gpu/ipc/common/gpu_preferences.mojom
+++ b/gpu/ipc/common/gpu_preferences.mojom
@@ -52,6 +52,7 @@
   bool gl_shader_interm_output;
   bool emulate_shader_precision;
   uint32 max_active_webgl_contexts;
+  bool enable_android_surface_control;
   bool enable_gpu_service_logging;
   bool enable_gpu_service_tracing;
   bool use_passthrough_cmd_decoder;
diff --git a/gpu/ipc/common/gpu_preferences_struct_traits.h b/gpu/ipc/common/gpu_preferences_struct_traits.h
index cc8afa7..648e33d 100644
--- a/gpu/ipc/common/gpu_preferences_struct_traits.h
+++ b/gpu/ipc/common/gpu_preferences_struct_traits.h
@@ -97,6 +97,8 @@
     out->gl_shader_interm_output = prefs.gl_shader_interm_output();
     out->emulate_shader_precision = prefs.emulate_shader_precision();
     out->max_active_webgl_contexts = prefs.max_active_webgl_contexts();
+    out->enable_android_surface_control =
+        prefs.enable_android_surface_control();
     out->enable_gpu_service_logging = prefs.enable_gpu_service_logging();
     out->enable_gpu_service_tracing = prefs.enable_gpu_service_tracing();
     out->use_passthrough_cmd_decoder = prefs.use_passthrough_cmd_decoder();
@@ -227,6 +229,9 @@
   static uint32_t max_active_webgl_contexts(const gpu::GpuPreferences& prefs) {
     return prefs.max_active_webgl_contexts;
   }
+  static bool enable_android_surface_control(const gpu::GpuPreferences& prefs) {
+    return prefs.enable_android_surface_control;
+  }
   static bool enable_gpu_service_logging(const gpu::GpuPreferences& prefs) {
     return prefs.enable_gpu_service_logging;
   }
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
index 031738c..84b4f7d2 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.cc
@@ -8,6 +8,7 @@
 #include "base/logging.h"
 #include "base/memory/shared_memory_handle.h"
 #include "build/build_config.h"
+#include "gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.h"
 #include "ui/gl/gl_image_ahardwarebuffer.h"
 
 namespace gpu {
@@ -26,13 +27,29 @@
     gfx::BufferUsage usage,
     int client_id,
     SurfaceHandle surface_handle) {
-  NOTIMPLEMENTED();
-  return gfx::GpuMemoryBufferHandle();
+  if (buffer_map_.find(id) != buffer_map_.end()) {
+    LOG(ERROR) << "Tried to create new GpuMemoryBuffer with an existing id";
+    return gfx::GpuMemoryBufferHandle();
+  }
+
+  auto buffer = GpuMemoryBufferImplAndroidHardwareBuffer::Create(
+      id, size, format, usage, GpuMemoryBufferImpl::DestructionCallback());
+  auto handle = buffer->CloneHandle();
+  buffer_map_[id] = std::move(buffer);
+  return handle;
 }
 
 void GpuMemoryBufferFactoryAndroidHardwareBuffer::DestroyGpuMemoryBuffer(
     gfx::GpuMemoryBufferId id,
-    int client_id) {}
+    int client_id) {
+  auto it = buffer_map_.find(id);
+  if (it == buffer_map_.end()) {
+    LOG(ERROR) << "Tried to delete non existent GpuMemoryBuffer";
+    return;
+  }
+
+  buffer_map_.erase(it);
+}
 
 ImageFactory* GpuMemoryBufferFactoryAndroidHardwareBuffer::AsImageFactory() {
   return this;
diff --git a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h
index fc7a862..3309e1c 100644
--- a/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h
+++ b/gpu/ipc/service/gpu_memory_buffer_factory_android_hardware_buffer.h
@@ -5,6 +5,7 @@
 #ifndef GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_ANDROID_HARDWARE_BUFFER_H_
 #define GPU_IPC_SERVICE_GPU_MEMORY_BUFFER_FACTORY_ANDROID_HARDWARE_BUFFER_H_
 
+#include "base/containers/flat_map.h"
 #include "gpu/command_buffer/service/image_factory.h"
 #include "gpu/ipc/service/gpu_ipc_service_export.h"
 #include "gpu/ipc/service/gpu_memory_buffer_factory.h"
@@ -14,6 +15,7 @@
 }
 
 namespace gpu {
+class GpuMemoryBufferImplAndroidHardwareBuffer;
 
 class GPU_IPC_SERVICE_EXPORT GpuMemoryBufferFactoryAndroidHardwareBuffer
     : public GpuMemoryBufferFactory,
@@ -35,6 +37,7 @@
   ImageFactory* AsImageFactory() override;
 
   // Overridden from ImageFactory:
+  // TODO(khushalsagar): Add support for anonymous images.
   scoped_refptr<gl::GLImage> CreateImageForGpuMemoryBuffer(
       gfx::GpuMemoryBufferHandle handle,
       const gfx::Size& size,
@@ -45,6 +48,11 @@
   unsigned RequiredTextureType() override;
 
  private:
+  using BufferMap =
+      base::flat_map<gfx::GpuMemoryBufferId,
+                     std::unique_ptr<GpuMemoryBufferImplAndroidHardwareBuffer>>;
+  BufferMap buffer_map_;
+
   DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferFactoryAndroidHardwareBuffer);
 };
 
diff --git a/gpu/ipc/service/image_transport_surface_android.cc b/gpu/ipc/service/image_transport_surface_android.cc
index 3312b44b..6443d2d 100644
--- a/gpu/ipc/service/image_transport_surface_android.cc
+++ b/gpu/ipc/service/image_transport_surface_android.cc
@@ -4,14 +4,16 @@
 
 #include "gpu/ipc/service/image_transport_surface.h"
 
+#include "base/feature_list.h"
 #include "base/logging.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/config/gpu_finch_features.h"
 #include "gpu/ipc/common/gpu_surface_lookup.h"
 #include "gpu/ipc/service/pass_through_image_transport_surface.h"
 #include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/gl_surface_egl_surface_control.h"
 #include "ui/gl/gl_surface_stub.h"
 
-#include <android/native_window.h>
-
 namespace gpu {
 
 // static
@@ -32,8 +34,15 @@
     LOG(WARNING) << "Failed to acquire native widget.";
     return nullptr;
   }
-  scoped_refptr<gl::GLSurface> surface =
-      new gl::NativeViewGLSurfaceEGL(window, nullptr);
+  scoped_refptr<gl::GLSurface> surface;
+
+  if (delegate &&
+      delegate->GetFeatureInfo()->feature_flags().android_surface_control) {
+    surface = new gl::GLSurfaceEGLSurfaceControl(window);
+  } else {
+    surface = new gl::NativeViewGLSurfaceEGL(window, nullptr);
+  }
+
   bool initialize_success = surface->Initialize(format);
   ANativeWindow_release(window);
   if (!initialize_success)
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index fd2d0da..77a4819 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -377,7 +377,6 @@
     "//ios/chrome/browser/ui/ntp:ntp_controller",
     "//ios/chrome/browser/ui/ntp:ntp_internal",
     "//ios/chrome/browser/ui/ntp:util",
-    "//ios/chrome/browser/ui/ntp/recent_tabs",
     "//ios/chrome/browser/ui/omnibox:omnibox_internal",
     "//ios/chrome/browser/ui/overscroll_actions",
     "//ios/chrome/browser/ui/page_info:coordinator",
diff --git a/ios/chrome/browser/ui/ntp/BUILD.gn b/ios/chrome/browser/ui/ntp/BUILD.gn
index af5e786..bb1de5f 100644
--- a/ios/chrome/browser/ui/ntp/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/BUILD.gn
@@ -41,7 +41,6 @@
     "//ios/chrome/browser/ui/content_suggestions",
     "//ios/chrome/browser/ui/content_suggestions:content_suggestions_constant",
     "//ios/chrome/browser/ui/content_suggestions:content_suggestions_ui_util",
-    "//ios/chrome/browser/ui/ntp/recent_tabs",
     "//ios/public/provider/chrome/browser/voice",
     "//ui/base",
   ]
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn
deleted file mode 100644
index cf6b842..0000000
--- a/ios/chrome/browser/ui/ntp/recent_tabs/BUILD.gn
+++ /dev/null
@@ -1,107 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("recent_tabs") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  sources = [
-    "closed_tabs_observer_bridge.h",
-    "closed_tabs_observer_bridge.mm",
-    "recent_tabs_constants.h",
-    "recent_tabs_constants.mm",
-    "recent_tabs_presentation_delegate.h",
-    "recent_tabs_table_consumer.h",
-    "recent_tabs_table_view_controller_delegate.h",
-    "sessions_sync_user_state.h",
-    "synced_sessions.h",
-    "synced_sessions.mm",
-  ]
-  deps = [
-    "//base",
-    "//components/browser_sync",
-    "//components/sessions",
-    "//components/strings",
-    "//components/sync",
-    "//ios/chrome/app/strings",
-    "//ios/chrome/app/theme",
-    "//ios/chrome/browser",
-    "//ios/chrome/browser/browser_state",
-    "//ios/chrome/browser/metrics:metrics_internal",
-    "//ios/chrome/browser/sessions",
-    "//ios/chrome/browser/sync",
-    "//ios/chrome/browser/ui",
-    "//ios/chrome/browser/ui/authentication",
-    "//ios/chrome/browser/ui/authentication:authentication_ui",
-    "//ios/chrome/browser/ui/commands",
-    "//ios/chrome/browser/ui/context_menu",
-    "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
-    "//ios/chrome/browser/ui/keyboard",
-    "//ios/chrome/browser/ui/ntp",
-    "//ios/chrome/browser/ui/ntp/recent_tabs/views",
-    "//ios/chrome/browser/ui/settings/sync_utils",
-    "//ios/chrome/browser/ui/signin_interaction/public",
-    "//ios/chrome/browser/ui/table_view",
-    "//ios/chrome/browser/ui/util",
-    "//ios/web",
-    "//ui/base",
-    "//url",
-  ]
-  public_deps = [
-    "//components/sync_sessions",
-  ]
-  allow_circular_includes_from =
-      [ "//ios/chrome/browser/ui/ntp/recent_tabs/views" ]
-  libs = [ "UIKit.framework" ]
-}
-
-source_set("unit_tests") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-  sources = [
-    "recent_tabs_coordinator_unittest.mm",
-  ]
-  deps = [
-    ":recent_tabs",
-    "//base",
-    "//components/browser_sync",
-    "//components/browser_sync:test_support",
-    "//components/signin/core/browser",
-    "//components/sync_sessions",
-    "//ios/chrome/browser/browser_state:test_support",
-    "//ios/chrome/browser/signin",
-    "//ios/chrome/browser/sync",
-    "//ios/chrome/browser/sync:test_support",
-    "//ios/chrome/browser/ui:feature_flags",
-    "//ios/chrome/browser/ui/ntp:ntp_internal",
-    "//ios/chrome/browser/ui/recent_tabs",
-    "//ios/chrome/test:test_support",
-    "//ios/web/public/test",
-    "//testing/gtest",
-    "//third_party/ocmock",
-  ]
-}
-
-source_set("eg_tests") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  testonly = true
-  sources = [
-    "recent_tabs_table_egtest.mm",
-  ]
-  deps = [
-    "//base/test:test_support",
-    "//components/strings",
-    "//ios/chrome/app/strings",
-    "//ios/chrome/browser/ui",
-    "//ios/chrome/browser/ui/authentication:eg_test_support",
-    "//ios/chrome/browser/ui/history:history_ui",
-    "//ios/chrome/browser/ui/ntp/recent_tabs",
-    "//ios/chrome/browser/ui/table_view",
-    "//ios/chrome/test/app:test_support",
-    "//ios/chrome/test/earl_grey:test_support",
-    "//ios/public/provider/chrome/browser/signin:test_support",
-    "//ios/third_party/earl_grey:earl_grey+link",
-    "//ios/web/public/test/http_server",
-    "//ui/base",
-  ]
-  libs = [ "XCTest.framework" ]
-}
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/BUILD.gn b/ios/chrome/browser/ui/ntp/recent_tabs/views/BUILD.gn
index 67d2c7c6..49bea373 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/BUILD.gn
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/BUILD.gn
@@ -46,6 +46,7 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/fancy_ui",
     "//ios/chrome/browser/ui/material_components",
+    "//ios/chrome/browser/ui/recent_tabs:recent_tabs_ui",
     "//ios/chrome/browser/ui/settings/sync_utils",
     "//ios/chrome/common/favicon",
     "//ios/third_party/material_components_ios",
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.mm
index 4951df3..240ae11c 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/generic_section_header_view.mm
@@ -6,9 +6,9 @@
 
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
-#include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
 #include "ios/chrome/browser/ui/ntp/recent_tabs/views/disclosure_view.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/views_utils.h"
+#include "ios/chrome/browser/ui/recent_tabs/synced_sessions.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.mm
index 88e31310..0cdf070 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_section_header_view.mm
@@ -6,9 +6,9 @@
 
 #include "base/logging.h"
 #include "base/strings/sys_string_conversions.h"
-#include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
 #include "ios/chrome/browser/ui/ntp/recent_tabs/views/disclosure_view.h"
 #include "ios/chrome/browser/ui/ntp/recent_tabs/views/views_utils.h"
+#include "ios/chrome/browser/ui/recent_tabs/synced_sessions.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/common/ui_util/constraints_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm
index 4186c09..710a53e 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/views/session_tab_data_view.mm
@@ -9,8 +9,8 @@
 #include "components/grit/components_scaled_resources.h"
 #import "ios/chrome/browser/favicon/favicon_loader.h"
 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
-#include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
 #import "ios/chrome/browser/ui/ntp/recent_tabs/views/views_utils.h"
+#include "ios/chrome/browser/ui/recent_tabs/synced_sessions.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #import "ios/chrome/common/favicon/favicon_attributes.h"
 #import "ios/chrome/common/favicon/favicon_view.h"
diff --git a/ios/chrome/browser/ui/recent_tabs/BUILD.gn b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
index 2dc9346..3db11af 100644
--- a/ios/chrome/browser/ui/recent_tabs/BUILD.gn
+++ b/ios/chrome/browser/ui/recent_tabs/BUILD.gn
@@ -5,6 +5,8 @@
 source_set("recent_tabs") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "closed_tabs_observer_bridge.h",
+    "closed_tabs_observer_bridge.mm",
     "recent_tabs_coordinator.h",
     "recent_tabs_coordinator.mm",
     "recent_tabs_mediator.h",
@@ -25,22 +27,31 @@
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/ntp",
-    "//ios/chrome/browser/ui/ntp/recent_tabs",
     "//ios/chrome/browser/ui/table_view",
     "//ios/chrome/browser/ui/util",
     "//ui/base",
   ]
-  allow_circular_includes_from = [ "//ios/chrome/browser/ui/ntp/recent_tabs" ]
+  public_deps = [
+    "//components/sync_sessions",
+  ]
 }
 
 source_set("recent_tabs_ui") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
+    "recent_tabs_constants.h",
+    "recent_tabs_constants.mm",
+    "recent_tabs_consumer.h",
     "recent_tabs_image_data_source.h",
+    "recent_tabs_presentation_delegate.h",
     "recent_tabs_table_view_controller.h",
     "recent_tabs_table_view_controller.mm",
+    "recent_tabs_table_view_controller_delegate.h",
     "recent_tabs_transitioning_delegate.h",
     "recent_tabs_transitioning_delegate.mm",
+    "sessions_sync_user_state.h",
+    "synced_sessions.h",
+    "synced_sessions.mm",
   ]
   deps = [
     "//base",
@@ -58,7 +69,6 @@
     "//ios/chrome/browser/ui/authentication:authentication_ui",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/context_menu",
-    "//ios/chrome/browser/ui/ntp/recent_tabs",
     "//ios/chrome/browser/ui/settings/sync_utils",
     "//ios/chrome/browser/ui/signin_interaction/public",
     "//ios/chrome/browser/ui/table_view",
@@ -67,4 +77,58 @@
     "//ios/chrome/common/favicon",
     "//ui/base",
   ]
+  public_deps = [
+    "//components/sync_sessions",
+  ]
+}
+
+source_set("unit_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "recent_tabs_coordinator_unittest.mm",
+  ]
+  deps = [
+    ":recent_tabs",
+    ":recent_tabs_ui",
+    "//base",
+    "//components/browser_sync",
+    "//components/browser_sync:test_support",
+    "//components/signin/core/browser",
+    "//components/sync_sessions",
+    "//ios/chrome/browser/browser_state:test_support",
+    "//ios/chrome/browser/signin",
+    "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/sync:test_support",
+    "//ios/chrome/browser/ui:feature_flags",
+    "//ios/chrome/test:test_support",
+    "//ios/web/public/test",
+    "//testing/gtest",
+    "//third_party/ocmock",
+  ]
+}
+
+source_set("eg_tests") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+  sources = [
+    "recent_tabs_egtest.mm",
+  ]
+  deps = [
+    ":recent_tabs_ui",
+    "//base/test:test_support",
+    "//components/strings",
+    "//ios/chrome/app/strings",
+    "//ios/chrome/browser/ui",
+    "//ios/chrome/browser/ui/authentication:eg_test_support",
+    "//ios/chrome/browser/ui/history:history_ui",
+    "//ios/chrome/browser/ui/table_view",
+    "//ios/chrome/test/app:test_support",
+    "//ios/chrome/test/earl_grey:test_support",
+    "//ios/public/provider/chrome/browser/signin:test_support",
+    "//ios/third_party/earl_grey:earl_grey+link",
+    "//ios/web/public/test/http_server",
+    "//ui/base",
+  ]
+  libs = [ "XCTest.framework" ]
 }
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.h b/ios/chrome/browser/ui/recent_tabs/closed_tabs_observer_bridge.h
similarity index 85%
rename from ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.h
rename to ios/chrome/browser/ui/recent_tabs/closed_tabs_observer_bridge.h
index 2c73b12..356a8a7 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.h
+++ b/ios/chrome/browser/ui/recent_tabs/closed_tabs_observer_bridge.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_CLOSED_TABS_OBSERVER_BRIDGE_H_
-#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_CLOSED_TABS_OBSERVER_BRIDGE_H_
+#ifndef IOS_CHROME_BROWSER_UI_RECENT_TABS_CLOSED_TABS_OBSERVER_BRIDGE_H_
+#define IOS_CHROME_BROWSER_UI_RECENT_TABS_CLOSED_TABS_OBSERVER_BRIDGE_H_
 
 #import <UIKit/UIKit.h>
 
@@ -40,4 +40,4 @@
 
 }  // namespace recent_tabs
 
-#endif  // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_CLOSED_TABS_OBSERVER_BRIDGE_H_
+#endif  // IOS_CHROME_BROWSER_UI_RECENT_TABS_CLOSED_TABS_OBSERVER_BRIDGE_H_
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.mm b/ios/chrome/browser/ui/recent_tabs/closed_tabs_observer_bridge.mm
similarity index 91%
rename from ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.mm
rename to ios/chrome/browser/ui/recent_tabs/closed_tabs_observer_bridge.mm
index 30450a87..f3e38bfe 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.mm
+++ b/ios/chrome/browser/ui/recent_tabs/closed_tabs_observer_bridge.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.h"
+#import "ios/chrome/browser/ui/recent_tabs/closed_tabs_observer_bridge.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h
similarity index 72%
rename from ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h
rename to ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h
index 3db70a5092..e8aeea71 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_CONSTANTS_H_
-#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_CONSTANTS_H_
+#ifndef IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_CONSTANTS_H_
+#define IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_CONSTANTS_H_
 
 #import <Foundation/Foundation.h>
 
@@ -14,4 +14,4 @@
 // Accessibility identifier for the "Show History" cell.
 extern NSString* const kRecentTabsShowFullHistoryCellAccessibilityIdentifier;
 
-#endif  // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_CONSTANTS_H_
+#endif  // IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.mm
similarity index 88%
rename from ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.mm
rename to ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.mm
index b83a421..5ce5ac3 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_consumer.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_consumer.h
similarity index 64%
rename from ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_consumer.h
rename to ios/chrome/browser/ui/recent_tabs/recent_tabs_consumer.h
index 99c6569..54135ff 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_consumer.h
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_consumer.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_CONSUMER_H_
-#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_CONSUMER_H_
+#ifndef IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_CONSUMER_H_
+#define IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_CONSUMER_H_
 
 #import <Foundation/Foundation.h>
 
-#import "ios/chrome/browser/ui/ntp/recent_tabs/sessions_sync_user_state.h"
+#import "ios/chrome/browser/ui/recent_tabs/sessions_sync_user_state.h"
 
 namespace sessions {
 class TabRestoreService;
 }
 
-// RecentTabs TableViewController public interface.
-@protocol RecentTabsTableConsumer<NSObject>
+// RecentTabs Consumer interface.
+@protocol RecentTabsConsumer<NSObject>
 
 // Refreshes the table view to match the current sync state.
 - (void)refreshUserState:(SessionsSyncUserState)state;
@@ -31,4 +31,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_CONSUMER_H_
+#endif  // IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_CONSUMER_H_
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
index 5110135e0..5cd15c5 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator.mm
@@ -7,8 +7,8 @@
 #include "base/ios/block_types.h"
 #include "base/mac/foundation_util.h"
 #include "ios/chrome/browser/ui/commands/application_commands.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_presentation_delegate.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_transitioning_delegate.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller.h"
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_coordinator_unittest.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator_unittest.mm
similarity index 98%
rename from ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_coordinator_unittest.mm
rename to ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator_unittest.mm
index fce2fcb7..eee894eb 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_coordinator_unittest.mm
@@ -19,7 +19,7 @@
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service_mock.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/sessions_sync_user_state.h"
+#import "ios/chrome/browser/ui/recent_tabs/sessions_sync_user_state.h"
 #include "ios/chrome/test/block_cleanup_test.h"
 #include "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_egtest.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
similarity index 97%
rename from ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_egtest.mm
rename to ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
index cb45878..d57436b 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_egtest.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
@@ -13,7 +13,7 @@
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
 #import "ios/chrome/browser/ui/history/history_ui_constants.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h"
 #import "ios/chrome/browser/ui/table_view/table_view_model.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_constants.h"
 #include "ios/chrome/browser/ui/ui_util.h"
@@ -62,10 +62,10 @@
 }  // namespace
 
 // Earl grey integration tests for Recent Tabs Panel Controller.
-@interface RecentTabsTableTestCase : ChromeTestCase
+@interface RecentTabsTestCase : ChromeTestCase
 @end
 
-@implementation RecentTabsTableTestCase
+@implementation RecentTabsTestCase
 
 - (void)setUp {
   [ChromeEarlGrey clearBrowsingHistory];
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h
index 7ce10668..08d40bd4 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h
@@ -8,21 +8,21 @@
 #import <Foundation/Foundation.h>
 
 #import "ios/chrome/browser/sync/synced_sessions_bridge.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/closed_tabs_observer_bridge.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller_delegate.h"
+#import "ios/chrome/browser/ui/recent_tabs/closed_tabs_observer_bridge.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_image_data_source.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_delegate.h"
 
 namespace ios {
 class ChromeBrowserState;
 }
 
-@protocol RecentTabsTableConsumer;
+@protocol RecentTabsConsumer;
 
-// RecentTabsMediator controls the RecentTabsTableConsumer,
+// RecentTabsMediator controls the RecentTabsConsumer,
 // based on the user's signed-in and chrome-sync states.
 //
 // RecentTabsMediator listens for notifications about Chrome Sync
-// and ChromeToDevice and changes/updates the RecentTabsTableConsumer
+// and ChromeToDevice and changes/updates the RecentTabsConsumer
 // accordingly.
 @interface RecentTabsMediator : NSObject<ClosedTabsObserving,
                                          RecentTabsTableViewControllerDelegate,
@@ -30,7 +30,7 @@
 
 // The consumer for this object. This can change during the lifetime of this
 // object and may be nil.
-@property(nonatomic, strong) id<RecentTabsTableConsumer> consumer;
+@property(nonatomic, strong) id<RecentTabsConsumer> consumer;
 
 // The coordinator's BrowserState.
 @property(nonatomic, assign) ios::ChromeBrowserState* browserState;
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.mm
index 985a150..277c7c6 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.mm
@@ -15,8 +15,8 @@
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_consumer.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/sessions_sync_user_state.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_consumer.h"
+#import "ios/chrome/browser/ui/recent_tabs/sessions_sync_user_state.h"
 #include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_presentation_delegate.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h
similarity index 76%
rename from ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_presentation_delegate.h
rename to ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h
index c46f0858..e4806412 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_presentation_delegate.h
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_PRESENTATION_DELEGATE_H_
-#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_PRESENTATION_DELEGATE_H_
+#ifndef IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_PRESENTATION_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_PRESENTATION_DELEGATE_H_
 
 #import <UIKit/UIKit.h>
 
@@ -21,4 +21,4 @@
 - (void)showHistoryFromRecentTabs;
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_PRESENTATION_DELEGATE_H_
+#endif  // IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_PRESENTATION_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
index 68241c1..0be4fae 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h
@@ -5,7 +5,7 @@
 #ifndef IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_H_
 #define IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_H_
 
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_consumer.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_consumer.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller.h"
 
 namespace ios {
@@ -19,7 +19,7 @@
 @protocol RecentTabsImageDataSource;
 
 @interface RecentTabsTableViewController
-    : ChromeTableViewController<RecentTabsTableConsumer>
+    : ChromeTableViewController<RecentTabsConsumer>
 // The coordinator's BrowserState.
 @property(nonatomic, assign) ios::ChromeBrowserState* browserState;
 // The dispatcher used by this ViewController.
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
index 5530e6a..bd108452 100644
--- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -27,11 +27,11 @@
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
 #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_presentation_delegate.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller_delegate.h"
-#include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_image_data_source.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_delegate.h"
+#include "ios/chrome/browser/ui/recent_tabs/synced_sessions.h"
 #import "ios/chrome/browser/ui/settings/sync_utils/sync_presenter.h"
 #import "ios/chrome/browser/ui/settings/sync_utils/sync_util.h"
 #import "ios/chrome/browser/ui/signin_interaction/public/signin_presenter.h"
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller_delegate.h b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_delegate.h
similarity index 60%
rename from ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller_delegate.h
rename to ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_delegate.h
index 8b7f1a6..ee7b42c 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_table_view_controller_delegate.h
+++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller_delegate.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_DELEGATE_H_
-#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_DELEGATE_H_
+#ifndef IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_DELEGATE_H_
+#define IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_DELEGATE_H_
 
 #import <Foundation/Foundation.h>
 
@@ -16,4 +16,4 @@
 
 @end
 
-#endif  // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_DELEGATE_H_
+#endif  // IOS_CHROME_BROWSER_UI_RECENT_TABS_RECENT_TABS_TABLE_VIEW_CONTROLLER_DELEGATE_H_
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/sessions_sync_user_state.h b/ios/chrome/browser/ui/recent_tabs/sessions_sync_user_state.h
similarity index 65%
rename from ios/chrome/browser/ui/ntp/recent_tabs/sessions_sync_user_state.h
rename to ios/chrome/browser/ui/recent_tabs/sessions_sync_user_state.h
index fd58319..21158c1 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/sessions_sync_user_state.h
+++ b/ios/chrome/browser/ui/recent_tabs/sessions_sync_user_state.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_SESSIONS_SYNC_USER_STATE_H_
-#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_SESSIONS_SYNC_USER_STATE_H_
+#ifndef IOS_CHROME_BROWSER_UI_RECENT_TABS_SESSIONS_SYNC_USER_STATE_H_
+#define IOS_CHROME_BROWSER_UI_RECENT_TABS_SESSIONS_SYNC_USER_STATE_H_
 
 // States listing the user's signed-in and sync status.
 enum class SessionsSyncUserState {
@@ -14,4 +14,4 @@
   USER_SIGNED_IN_SYNC_ON_WITH_SESSIONS,
 };
 
-#endif  // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_SESSIONS_SYNC_USER_STATE_H_
+#endif  // IOS_CHROME_BROWSER_UI_RECENT_TABS_SESSIONS_SYNC_USER_STATE_H_
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h b/ios/chrome/browser/ui/recent_tabs/synced_sessions.h
similarity index 93%
rename from ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h
rename to ios/chrome/browser/ui/recent_tabs/synced_sessions.h
index 4590ff8..6cb2be8 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h
+++ b/ios/chrome/browser/ui/recent_tabs/synced_sessions.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_SYNCED_SESSIONS_H_
-#define IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_SYNCED_SESSIONS_H_
+#ifndef IOS_CHROME_BROWSER_UI_RECENT_TABS_SYNCED_SESSIONS_H_
+#define IOS_CHROME_BROWSER_UI_RECENT_TABS_SYNCED_SESSIONS_H_
 
 #include <memory>
 #include <string>
@@ -93,4 +93,4 @@
 
 }  // namespace synced_sessions
 
-#endif  // IOS_CHROME_BROWSER_UI_NTP_RECENT_TABS_SYNCED_SESSIONS_H_
+#endif  // IOS_CHROME_BROWSER_UI_RECENT_TABS_SYNCED_SESSIONS_H_
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.mm b/ios/chrome/browser/ui/recent_tabs/synced_sessions.mm
similarity index 98%
rename from ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.mm
rename to ios/chrome/browser/ui/recent_tabs/synced_sessions.mm
index 424b47a27..ee59b8e 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.mm
+++ b/ios/chrome/browser/ui/recent_tabs/synced_sessions.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/chrome/browser/ui/ntp/recent_tabs/synced_sessions.h"
+#include "ios/chrome/browser/ui/recent_tabs/synced_sessions.h"
 
 #include <functional>
 #include <memory>
diff --git a/ios/chrome/browser/ui/tab_grid/BUILD.gn b/ios/chrome/browser/ui/tab_grid/BUILD.gn
index 951e06b5..f15cafd 100644
--- a/ios/chrome/browser/ui/tab_grid/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_grid/BUILD.gn
@@ -37,7 +37,6 @@
     "//ios/chrome/browser/ui/history/public",
     "//ios/chrome/browser/ui/main",
     "//ios/chrome/browser/ui/main:tab_switcher",
-    "//ios/chrome/browser/ui/ntp/recent_tabs",
     "//ios/chrome/browser/ui/recent_tabs",
     "//ios/chrome/browser/ui/recent_tabs:recent_tabs_ui",
     "//ios/chrome/browser/web",
@@ -136,7 +135,7 @@
     "//base/test:test_support",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui:ui_util",
-    "//ios/chrome/browser/ui/ntp/recent_tabs",
+    "//ios/chrome/browser/ui/recent_tabs:recent_tabs_ui",
     "//ios/chrome/test/app:test_support",
     "//ios/chrome/test/earl_grey:test_support",
     "//ios/third_party/earl_grey:earl_grey+link",
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
index 456826da..f1e635c3 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_coordinator.mm
@@ -17,8 +17,8 @@
 #import "ios/chrome/browser/ui/history/history_coordinator.h"
 #import "ios/chrome/browser/ui/history/public/history_presentation_delegate.h"
 #import "ios/chrome/browser/ui/main/bvc_container_view_controller.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_presentation_delegate.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_mediator.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_presentation_delegate.h"
 #import "ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_adaptor.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_mediator.h"
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_egtest_util.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_egtest_util.mm
index 02b3d1a..a50ae75 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_egtest_util.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_egtest_util.mm
@@ -6,7 +6,7 @@
 
 #import <EarlGrey/EarlGrey.h>
 
-#import "ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_constants.h"
+#import "ios/chrome/browser/ui/recent_tabs/recent_tabs_constants.h"
 #import "ios/chrome/browser/ui/tab_grid/grid/grid_constants.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_constants.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
index 93d1e6f..38929a9f 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_view_controller.h
@@ -14,7 +14,7 @@
 @protocol GridConsumer;
 @protocol GridCommands;
 @protocol GridImageDataSource;
-@protocol RecentTabsTableConsumer;
+@protocol RecentTabsConsumer;
 @class RecentTabsTableViewController;
 
 // Delegate protocol for an object that can handle presenting ("opening") tabs
@@ -38,7 +38,7 @@
 // Consumers send updates from the model layer to the UI layer.
 @property(nonatomic, readonly) id<GridConsumer> regularTabsConsumer;
 @property(nonatomic, readonly) id<GridConsumer> incognitoTabsConsumer;
-@property(nonatomic, readonly) id<RecentTabsTableConsumer> remoteTabsConsumer;
+@property(nonatomic, readonly) id<RecentTabsConsumer> remoteTabsConsumer;
 
 // Delegates send updates from the UI layer to the model layer.
 @property(nonatomic, weak) id<GridCommands> regularTabsDelegate;
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 9a7340ad..f107e75 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
@@ -443,7 +443,7 @@
   _incognitoTabsImageDataSource = incognitoTabsImageDataSource;
 }
 
-- (id<RecentTabsTableConsumer>)remoteTabsConsumer {
+- (id<RecentTabsConsumer>)remoteTabsConsumer {
   return self.remoteTabsViewController;
 }
 
diff --git a/ios/chrome/test/BUILD.gn b/ios/chrome/test/BUILD.gn
index 4121f34..5ea51c8 100644
--- a/ios/chrome/test/BUILD.gn
+++ b/ios/chrome/test/BUILD.gn
@@ -212,7 +212,6 @@
     "//ios/chrome/browser/ui/main:unit_tests",
     "//ios/chrome/browser/ui/main_content:unit_tests",
     "//ios/chrome/browser/ui/ntp:unit_tests",
-    "//ios/chrome/browser/ui/ntp/recent_tabs:unit_tests",
     "//ios/chrome/browser/ui/omnibox:unit_tests",
     "//ios/chrome/browser/ui/omnibox/popup:unit_tests",
     "//ios/chrome/browser/ui/overlays:unit_tests",
@@ -223,6 +222,7 @@
     "//ios/chrome/browser/ui/promos:unit_tests",
     "//ios/chrome/browser/ui/qr_scanner:unit_tests",
     "//ios/chrome/browser/ui/reading_list:unit_tests",
+    "//ios/chrome/browser/ui/recent_tabs:unit_tests",
     "//ios/chrome/browser/ui/safe_mode:unit_tests",
     "//ios/chrome/browser/ui/settings:unit_tests",
     "//ios/chrome/browser/ui/settings/cells:unit_tests",
diff --git a/ios/chrome/test/earl_grey/BUILD.gn b/ios/chrome/test/earl_grey/BUILD.gn
index 885664c4a..deb8ccc 100644
--- a/ios/chrome/test/earl_grey/BUILD.gn
+++ b/ios/chrome/test/earl_grey/BUILD.gn
@@ -115,10 +115,10 @@
     "//ios/chrome/browser/ui/history:eg_tests",
     "//ios/chrome/browser/ui/infobars:eg_tests",
     "//ios/chrome/browser/ui/ntp:eg_tests",
-    "//ios/chrome/browser/ui/ntp/recent_tabs:eg_tests",
     "//ios/chrome/browser/ui/popup_menu:eg_tests",
     "//ios/chrome/browser/ui/print:eg_tests",
     "//ios/chrome/browser/ui/qr_scanner:eg_tests",
+    "//ios/chrome/browser/ui/recent_tabs:eg_tests",
     "//ios/chrome/browser/ui/sad_tab:eg_tests",
     "//ios/chrome/browser/ui/safe_mode:eg_tests",
     "//ios/chrome/browser/ui/settings/sync_utils:eg_tests",
diff --git a/jingle/BUILD.gn b/jingle/BUILD.gn
index 3ece7ca1a..2e28153 100644
--- a/jingle/BUILD.gn
+++ b/jingle/BUILD.gn
@@ -197,6 +197,7 @@
     "//base/test:test_support",
     "//net",
     "//net:test_support",
+    "//services/network:test_support",
     "//testing/gmock",
     "//testing/gtest",
   ]
diff --git a/jingle/notifier/base/notifier_options.cc b/jingle/notifier/base/notifier_options.cc
index 9a149a3c..edb7ac6 100644
--- a/jingle/notifier/base/notifier_options.cc
+++ b/jingle/notifier/base/notifier_options.cc
@@ -13,7 +13,8 @@
       allow_insecure_connection(false),
       invalidate_xmpp_login(false),
       notification_method(kDefaultNotificationMethod),
-      auth_mechanism(kDefaultGaiaAuthMechanism) {}
+      auth_mechanism(kDefaultGaiaAuthMechanism),
+      network_connection_tracker(nullptr) {}
 
 NotifierOptions::NotifierOptions(const NotifierOptions& other) = default;
 
diff --git a/jingle/notifier/base/notifier_options.h b/jingle/notifier/base/notifier_options.h
index 08f03a8..e0ff533 100644
--- a/jingle/notifier/base/notifier_options.h
+++ b/jingle/notifier/base/notifier_options.h
@@ -12,6 +12,10 @@
 #include "net/base/host_port_pair.h"
 #include "net/url_request/url_request_context_getter.h"
 
+namespace network {
+class NetworkConnectionTracker;
+}
+
 namespace notifier {
 
 struct NotifierOptions {
@@ -44,6 +48,9 @@
 
   // The URLRequestContextGetter to use for doing I/O.
   scoped_refptr<net::URLRequestContextGetter> request_context_getter;
+
+  // Used to listen for network connection changes.
+  network::NetworkConnectionTracker* network_connection_tracker;
 };
 
 }  // namespace notifier
diff --git a/jingle/notifier/communicator/DEPS b/jingle/notifier/communicator/DEPS
index ebe0a7b6..1c049cb 100644
--- a/jingle/notifier/communicator/DEPS
+++ b/jingle/notifier/communicator/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+services/network/public/cpp",
   # Need for cricket::ProtocolType.
   "+webrtc/p2p/base/port.h",
 ]
diff --git a/jingle/notifier/communicator/login.cc b/jingle/notifier/communicator/login.cc
index 7e10c4f..2dad930 100644
--- a/jingle/notifier/communicator/login.cc
+++ b/jingle/notifier/communicator/login.cc
@@ -32,21 +32,25 @@
     const ServerList& servers,
     bool try_ssltcp_first,
     const std::string& auth_mechanism,
-    const net::NetworkTrafficAnnotationTag& traffic_annotation)
+    const net::NetworkTrafficAnnotationTag& traffic_annotation,
+    network::NetworkConnectionTracker* network_connection_tracker)
     : delegate_(delegate),
       login_settings_(user_settings,
                       request_context_getter,
                       servers,
                       try_ssltcp_first,
                       auth_mechanism,
-                      traffic_annotation) {
-  net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+                      traffic_annotation),
+      network_connection_tracker_(network_connection_tracker) {
+  if (network_connection_tracker_)
+    network_connection_tracker_->AddNetworkConnectionObserver(this);
   // TODO(akalin): Add as DNSObserver once bug 130610 is fixed.
   ResetReconnectState();
 }
 
 Login::~Login() {
-  net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+  if (network_connection_tracker_)
+    network_connection_tracker_->RemoveNetworkConnectionObserver(this);
 }
 
 void Login::StartConnection() {
@@ -90,8 +94,8 @@
   delegate_->OnTransientDisconnection();
 }
 
-void Login::OnNetworkChanged(net::NetworkChangeNotifier::ConnectionType type) {
-  if (type == net::NetworkChangeNotifier::CONNECTION_NONE)
+void Login::OnConnectionChanged(network::mojom::ConnectionType type) {
+  if (type == network::mojom::ConnectionType::CONNECTION_NONE)
     return;
 
   DVLOG(1) << "Network changed";
diff --git a/jingle/notifier/communicator/login.h b/jingle/notifier/communicator/login.h
index d57de09..fe4f46f 100644
--- a/jingle/notifier/communicator/login.h
+++ b/jingle/notifier/communicator/login.h
@@ -19,6 +19,7 @@
 #include "jingle/notifier/communicator/single_login_attempt.h"
 #include "net/base/network_change_notifier.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/network_connection_tracker.h"
 #include "third_party/libjingle_xmpp/xmpp/xmppengine.h"
 
 namespace buzz {
@@ -39,9 +40,10 @@
 // to take on the various errors that may occur.
 //
 // TODO(akalin): Make this observe proxy config changes also.
-class Login : public net::NetworkChangeNotifier::NetworkChangeObserver,
-              public net::NetworkChangeNotifier::DNSObserver,
-              public SingleLoginAttempt::Delegate {
+class Login
+    : public network::NetworkConnectionTracker::NetworkConnectionObserver,
+      public net::NetworkChangeNotifier::DNSObserver,
+      public SingleLoginAttempt::Delegate {
  public:
   class Delegate {
    public:
@@ -72,7 +74,8 @@
       const ServerList& servers,
       bool try_ssltcp_first,
       const std::string& auth_mechanism,
-      const net::NetworkTrafficAnnotationTag& traffic_annotation);
+      const net::NetworkTrafficAnnotationTag& traffic_annotation,
+      network::NetworkConnectionTracker* network_connection_tracker);
   ~Login() override;
 
   // Starts connecting (or forces a reconnection if we're backed off).
@@ -83,9 +86,8 @@
   // StartConnection()).
   void UpdateXmppSettings(const buzz::XmppClientSettings& user_settings);
 
-  // net::NetworkChangeNotifier::NetworkChangeObserver implementation.
-  void OnNetworkChanged(
-      net::NetworkChangeNotifier::ConnectionType type) override;
+  // network::NetworkConnectionTracker::NetworkConnectionObserver implementation
+  void OnConnectionChanged(network::mojom::ConnectionType type) override;
 
   // net::NetworkChangeNotifier::DNSObserver implementation.
   void OnDNSChanged() override;
@@ -115,6 +117,7 @@
 
   Delegate* const delegate_;
   LoginSettings login_settings_;
+  network::NetworkConnectionTracker* network_connection_tracker_;
   std::unique_ptr<SingleLoginAttempt> single_attempt_;
 
   // reconnection state.
diff --git a/jingle/notifier/listener/xmpp_push_client.cc b/jingle/notifier/listener/xmpp_push_client.cc
index 5c51fe2..64f2ae0 100644
--- a/jingle/notifier/listener/xmpp_push_client.cc
+++ b/jingle/notifier/listener/xmpp_push_client.cc
@@ -131,7 +131,8 @@
     login_.reset(new notifier::Login(
         this, xmpp_settings_, notifier_options_.request_context_getter,
         GetServerList(notifier_options_), notifier_options_.try_ssltcp_first,
-        notifier_options_.auth_mechanism, traffic_annotation));
+        notifier_options_.auth_mechanism, traffic_annotation,
+        notifier_options_.network_connection_tracker));
     login_->StartConnection();
   }
 }
diff --git a/media/audio/audio_manager_unittest.cc b/media/audio/audio_manager_unittest.cc
index b6d7e789..6271c1fb 100644
--- a/media/audio/audio_manager_unittest.cc
+++ b/media/audio/audio_manager_unittest.cc
@@ -294,7 +294,7 @@
       const AudioDeviceDescriptions& device_descriptions) {
     DVLOG(2) << "Got " << device_descriptions.size() << " audio devices.";
     if (!device_descriptions.empty()) {
-      AudioDeviceDescriptions::const_iterator it = device_descriptions.begin();
+      auto it = device_descriptions.begin();
 
       // The first device in the list should always be the default device.
       EXPECT_EQ(std::string(AudioDeviceDescription::kDefaultDeviceId),
diff --git a/media/audio/audio_output_dispatcher_impl.cc b/media/audio/audio_output_dispatcher_impl.cc
index c955993..932be81 100644
--- a/media/audio/audio_output_dispatcher_impl.cc
+++ b/media/audio/audio_output_dispatcher_impl.cc
@@ -101,7 +101,7 @@
 
 void AudioOutputDispatcherImpl::StopStream(AudioOutputProxy* stream_proxy) {
   DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
-  AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
+  auto it = proxy_to_physical_map_.find(stream_proxy);
   DCHECK(it != proxy_to_physical_map_.end());
   StopPhysicalStream(it->second);
   proxy_to_physical_map_.erase(it);
@@ -111,7 +111,7 @@
 void AudioOutputDispatcherImpl::StreamVolumeSet(AudioOutputProxy* stream_proxy,
                                                 double volume) {
   DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
-  AudioStreamMap::iterator it = proxy_to_physical_map_.find(stream_proxy);
+  auto it = proxy_to_physical_map_.find(stream_proxy);
   if (it != proxy_to_physical_map_.end()) {
     AudioOutputStream* physical_stream = it->second;
     physical_stream->SetVolume(volume);
diff --git a/media/audio/audio_output_resampler.cc b/media/audio/audio_output_resampler.cc
index 32853fe0..67aa3b75 100644
--- a/media/audio/audio_output_resampler.cc
+++ b/media/audio/audio_output_resampler.cc
@@ -409,7 +409,7 @@
   DCHECK(dispatcher_);
 
   OnMoreDataConverter* resampler_callback = nullptr;
-  CallbackMap::iterator it = callbacks_.find(stream_proxy);
+  auto it = callbacks_.find(stream_proxy);
   if (it == callbacks_.end()) {
     // If a register callback has been given, register and pass the returned
     // recoder to the converter. Data is fed to same recorder for the lifetime
@@ -440,7 +440,7 @@
 void AudioOutputResampler::StopStream(AudioOutputProxy* stream_proxy) {
   DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
 
-  CallbackMap::iterator it = callbacks_.find(stream_proxy);
+  auto it = callbacks_.find(stream_proxy);
   DCHECK(it != callbacks_.end());
   StopStreamInternal(*it);
 }
diff --git a/media/audio/virtual_audio_input_stream.cc b/media/audio/virtual_audio_input_stream.cc
index ee4239d0..7c8ca14b 100644
--- a/media/audio/virtual_audio_input_stream.cc
+++ b/media/audio/virtual_audio_input_stream.cc
@@ -41,8 +41,7 @@
   // output streams be removed before VirtualAudioInputStream is destroyed.
   DCHECK_EQ(0, num_attached_output_streams_);
 
-  for (AudioConvertersMap::iterator it = converters_.begin();
-       it != converters_.end(); ++it) {
+  for (auto it = converters_.begin(); it != converters_.end(); ++it) {
     delete it->second;
   }
 }
@@ -72,7 +71,7 @@
 
   base::AutoLock scoped_lock(converter_network_lock_);
 
-  AudioConvertersMap::iterator converter = converters_.find(params);
+  auto converter = converters_.find(params);
   if (converter == converters_.end()) {
     std::pair<AudioConvertersMap::iterator, bool> result =
         converters_.insert(std::make_pair(
diff --git a/media/base/audio_renderer_mixer.cc b/media/base/audio_renderer_mixer.cc
index 2c22946f..0741ca90 100644
--- a/media/base/audio_renderer_mixer.cc
+++ b/media/base/audio_renderer_mixer.cc
@@ -89,8 +89,7 @@
   if (is_master_sample_rate(input_sample_rate)) {
     master_converter_.AddInput(input);
   } else {
-    AudioConvertersMap::iterator converter =
-        converters_.find(input_sample_rate);
+    auto converter = converters_.find(input_sample_rate);
     if (converter == converters_.end()) {
       std::pair<AudioConvertersMap::iterator, bool> result =
           converters_.insert(std::make_pair(
@@ -120,8 +119,7 @@
   if (is_master_sample_rate(input_sample_rate)) {
     master_converter_.RemoveInput(input);
   } else {
-    AudioConvertersMap::iterator converter =
-        converters_.find(input_sample_rate);
+    auto converter = converters_.find(input_sample_rate);
     DCHECK(converter != converters_.end());
     converter->second->RemoveInput(input);
     if (converter->second->empty()) {
@@ -141,9 +139,7 @@
 
 void AudioRendererMixer::RemoveErrorCallback(const base::Closure& error_cb) {
   base::AutoLock auto_lock(lock_);
-  for (ErrorCallbackList::iterator it = error_callbacks_.begin();
-       it != error_callbacks_.end();
-       ++it) {
+  for (auto it = error_callbacks_.begin(); it != error_callbacks_.end(); ++it) {
     if (it->Equals(error_cb)) {
       error_callbacks_.erase(it);
       return;
diff --git a/media/base/cdm_promise_adapter.cc b/media/base/cdm_promise_adapter.cc
index dfc22ed..3ff34ee 100644
--- a/media/base/cdm_promise_adapter.cc
+++ b/media/base/cdm_promise_adapter.cc
@@ -74,7 +74,7 @@
 std::unique_ptr<CdmPromise> CdmPromiseAdapter::TakePromise(
     uint32_t promise_id) {
   DCHECK(thread_checker_.CalledOnValidThread());
-  PromiseMap::iterator it = promises_.find(promise_id);
+  auto it = promises_.find(promise_id);
   if (it == promises_.end())
     return nullptr;
   std::unique_ptr<CdmPromise> result = std::move(it->second);
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc
index 9cf3dd8..b1657e57 100644
--- a/media/base/key_systems.cc
+++ b/media/base/key_systems.cc
@@ -319,8 +319,7 @@
 
 SupportedCodecs KeySystemsImpl::GetCodecMaskForMimeType(
     const std::string& container_mime_type) const {
-  MimeTypeToCodecsMap::const_iterator iter =
-      mime_type_to_codecs_map_.find(container_mime_type);
+  auto iter = mime_type_to_codecs_map_.find(container_mime_type);
   if (iter == mime_type_to_codecs_map_.end())
     return EME_CODEC_NONE;
 
@@ -329,7 +328,7 @@
 }
 
 EmeCodec KeySystemsImpl::GetCodecForString(const std::string& codec) const {
-  CodecMap::const_iterator iter = codec_map_.find(codec);
+  auto iter = codec_map_.find(codec);
   if (iter != codec_map_.end())
     return iter->second;
   return EME_CODEC_NONE;
@@ -491,8 +490,7 @@
     EmeInitDataType init_data_type) const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  KeySystemPropertiesMap::const_iterator key_system_iter =
-      key_system_properties_map_.find(key_system);
+  auto key_system_iter = key_system_properties_map_.find(key_system);
   if (key_system_iter == key_system_properties_map_.end()) {
     NOTREACHED();
     return false;
@@ -505,8 +503,7 @@
     EncryptionMode encryption_scheme) const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  KeySystemPropertiesMap::const_iterator key_system_iter =
-      key_system_properties_map_.find(key_system);
+  auto key_system_iter = key_system_properties_map_.find(key_system);
   if (key_system_iter == key_system_properties_map_.end()) {
     NOTREACHED();
     return EmeConfigRule::NOT_SUPPORTED;
@@ -561,8 +558,7 @@
 bool KeySystemsImpl::CanUseAesDecryptor(const std::string& key_system) const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  KeySystemPropertiesMap::const_iterator key_system_iter =
-      key_system_properties_map_.find(key_system);
+  auto key_system_iter = key_system_properties_map_.find(key_system);
   if (key_system_iter == key_system_properties_map_.end()) {
     DLOG(ERROR) << key_system << " is not a known key system";
     return false;
@@ -592,8 +588,7 @@
   }
 
   // Double check whether the key system is supported.
-  KeySystemPropertiesMap::const_iterator key_system_iter =
-      key_system_properties_map_.find(key_system);
+  auto key_system_iter = key_system_properties_map_.find(key_system);
   if (key_system_iter == key_system_properties_map_.end()) {
     NOTREACHED()
         << "KeySystemConfigSelector should've checked key system support";
@@ -652,8 +647,7 @@
     const std::string& requested_robustness) const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  KeySystemPropertiesMap::const_iterator key_system_iter =
-      key_system_properties_map_.find(key_system);
+  auto key_system_iter = key_system_properties_map_.find(key_system);
   if (key_system_iter == key_system_properties_map_.end()) {
     NOTREACHED();
     return EmeConfigRule::NOT_SUPPORTED;
@@ -666,8 +660,7 @@
     const std::string& key_system) const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  KeySystemPropertiesMap::const_iterator key_system_iter =
-      key_system_properties_map_.find(key_system);
+  auto key_system_iter = key_system_properties_map_.find(key_system);
   if (key_system_iter == key_system_properties_map_.end()) {
     NOTREACHED();
     return EmeSessionTypeSupport::INVALID;
@@ -679,8 +672,7 @@
     const std::string& key_system) const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  KeySystemPropertiesMap::const_iterator key_system_iter =
-      key_system_properties_map_.find(key_system);
+  auto key_system_iter = key_system_properties_map_.find(key_system);
   if (key_system_iter == key_system_properties_map_.end()) {
     NOTREACHED();
     return EmeSessionTypeSupport::INVALID;
@@ -692,8 +684,7 @@
     const std::string& key_system) const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  KeySystemPropertiesMap::const_iterator key_system_iter =
-      key_system_properties_map_.find(key_system);
+  auto key_system_iter = key_system_properties_map_.find(key_system);
   if (key_system_iter == key_system_properties_map_.end()) {
     NOTREACHED();
     return EmeFeatureSupport::INVALID;
@@ -705,8 +696,7 @@
     const std::string& key_system) const {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  KeySystemPropertiesMap::const_iterator key_system_iter =
-      key_system_properties_map_.find(key_system);
+  auto key_system_iter = key_system_properties_map_.find(key_system);
   if (key_system_iter == key_system_properties_map_.end()) {
     NOTREACHED();
     return EmeFeatureSupport::INVALID;
diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc
index a1bba5f..507384d 100644
--- a/media/base/mime_util_internal.cc
+++ b/media/base/mime_util_internal.cc
@@ -409,8 +409,7 @@
     return;
 
   // Strip everything past the first '.'
-  for (std::vector<std::string>::iterator it = codecs_out->begin();
-       it != codecs_out->end(); ++it) {
+  for (auto it = codecs_out->begin(); it != codecs_out->end(); ++it) {
     size_t found = it->find_first_of('.');
     if (found != std::string::npos)
       it->resize(found);
@@ -685,8 +684,7 @@
   DCHECK(out_results);
 
   // Reject unrecognized mime types.
-  MediaFormatMappings::const_iterator it_media_format_map =
-      media_format_map_.find(mime_type_lower_case);
+  auto it_media_format_map = media_format_map_.find(mime_type_lower_case);
   if (it_media_format_map == media_format_map_.end()) {
     DVLOG(3) << __func__ << " Unrecognized mime type: " << mime_type_lower_case;
     return false;
@@ -764,8 +762,7 @@
   *out_result = MakeDefaultParsedCodecResult();
 
   // Simple codecs can be found in the codec map.
-  base::flat_map<std::string, Codec>::const_iterator itr =
-      GetStringToCodecMap().find(codec_id);
+  auto itr = GetStringToCodecMap().find(codec_id);
   if (itr != GetStringToCodecMap().end()) {
     out_result->codec = itr->second;
 
diff --git a/media/base/seekable_buffer.cc b/media/base/seekable_buffer.cc
index fb3f4d2..1828920 100644
--- a/media/base/seekable_buffer.cc
+++ b/media/base/seekable_buffer.cc
@@ -168,7 +168,7 @@
 void SeekableBuffer::EvictBackwardBuffers() {
   // Advances the iterator until we hit the current pointer.
   while (backward_bytes_ > backward_capacity_) {
-    BufferQueue::iterator i = buffers_.begin();
+    auto i = buffers_.begin();
     if (i == current_buffer_)
       break;
     scoped_refptr<DataBuffer> buffer = *i;
@@ -186,7 +186,7 @@
   // Counts how many bytes are actually read from the buffer queue.
   int taken = 0;
 
-  BufferQueue::iterator current_buffer = current_buffer_;
+  auto current_buffer = current_buffer_;
   int current_buffer_offset = current_buffer_offset_;
 
   int bytes_to_skip = forward_offset;
@@ -232,7 +232,7 @@
         UpdateCurrentTime(current_buffer, current_buffer_offset);
       }
 
-      BufferQueue::iterator next = current_buffer;
+      auto next = current_buffer;
       ++next;
       // If we are at the last buffer, don't advance.
       if (next == buffers_.end())
diff --git a/media/base/test_data_util.cc b/media/base/test_data_util.cc
index 6ca9aa9..2a53b13 100644
--- a/media/base/test_data_util.cc
+++ b/media/base/test_data_util.cc
@@ -53,7 +53,7 @@
 
 std::string GetURLQueryString(const base::StringPairs& query_params) {
   std::string query = "";
-  base::StringPairs::const_iterator itr = query_params.begin();
+  auto itr = query_params.begin();
   for (; itr != query_params.end(); ++itr) {
     if (itr != query_params.begin())
       query.append("&");
diff --git a/media/base/text_renderer_unittest.cc b/media/base/text_renderer_unittest.cc
index e6348ea..be327b67 100644
--- a/media/base/text_renderer_unittest.cc
+++ b/media/base/text_renderer_unittest.cc
@@ -110,7 +110,7 @@
                            const std::string& id,
                            const std::string& content,
                            const std::string& settings) {
-    for (TextTrackStreams::iterator itr = text_track_streams_.begin();
+    for (auto itr = text_track_streams_.begin();
          itr != text_track_streams_.end(); ++itr) {
       (*itr)->SatisfyPendingRead(start, duration, id, content, settings);
     }
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc
index 203103b..2d47276 100644
--- a/media/blink/cdm_session_adapter.cc
+++ b/media/blink/cdm_session_adapter.cc
@@ -258,7 +258,7 @@
   // Since session objects may get garbage collected, it is possible that there
   // are events coming back from the CDM and the session has been unregistered.
   // We can not tell if the CDM is firing events at sessions that never existed.
-  SessionMap::iterator session = sessions_.find(session_id);
+  auto session = sessions_.find(session_id);
   return (session != sessions_.end()) ? session->second.get() : NULL;
 }
 
diff --git a/media/blink/lru_unittest.cc b/media/blink/lru_unittest.cc
index afb6c354..3255ece1 100644
--- a/media/blink/lru_unittest.cc
+++ b/media/blink/lru_unittest.cc
@@ -27,7 +27,7 @@
   }
 
   void Remove(int x) {
-    for (std::list<int>::iterator i = data_.begin(); i != data_.end(); ++i) {
+    for (auto i = data_.begin(); i != data_.end(); ++i) {
       if (*i == x) {
         data_.erase(i);
         DCHECK(!Contains(x));
@@ -58,8 +58,7 @@
   }
 
   bool Contains(int x) const {
-    for (std::list<int>::const_iterator i = data_.begin(); i != data_.end();
-         ++i) {
+    for (auto i = data_.begin(); i != data_.end(); ++i) {
       if (*i == x) {
         return true;
       }
diff --git a/media/blink/multibuffer_unittest.cc b/media/blink/multibuffer_unittest.cc
index 715adf1..773e239 100644
--- a/media/blink/multibuffer_unittest.cc
+++ b/media/blink/multibuffer_unittest.cc
@@ -143,7 +143,7 @@
 
   void CheckPresentState() {
     IntervalMap<MultiBufferBlockId, int32_t> tmp;
-    for (DataMap::iterator i = data_.begin(); i != data_.end(); ++i) {
+    for (auto i = data_.begin(); i != data_.end(); ++i) {
       CHECK(i->second);  // Null poineters are not allowed in data_
       CHECK_NE(!!pinned_[i->first], lru_->Contains(this, i->first))
           << " i->first = " << i->first;
@@ -166,7 +166,7 @@
   }
 
   void CheckLRUState() {
-    for (DataMap::iterator i = data_.begin(); i != data_.end(); ++i) {
+    for (auto i = data_.begin(); i != data_.end(); ++i) {
       CHECK(i->second);  // Null poineters are not allowed in data_
       CHECK_NE(!!pinned_[i->first], lru_->Contains(this, i->first))
           << " i->first = " << i->first;
diff --git a/media/capture/content/animated_content_sampler_unittest.cc b/media/capture/content/animated_content_sampler_unittest.cc
index 10f5dc8..37f1fa8e 100644
--- a/media/capture/content/animated_content_sampler_unittest.cc
+++ b/media/capture/content/animated_content_sampler_unittest.cc
@@ -327,8 +327,7 @@
     bool has_detection_switched = false;
     bool has_detection_flip_flopped_once = false;
     ResetFrameCounters();
-    for (std::vector<Event>::const_iterator i = events.begin();
-         i != events.end(); ++i) {
+    for (auto i = events.begin(); i != events.end(); ++i) {
       sampler()->ConsiderPresentationEvent(i->first, i->second);
 
       // Detect when the sampler locks in/out, and that it stays that way for
diff --git a/media/capture/video/linux/v4l2_capture_delegate.cc b/media/capture/video/linux/v4l2_capture_delegate.cc
index 902903b..8b634c4 100644
--- a/media/capture/video/linux/v4l2_capture_delegate.cc
+++ b/media/capture/video/linux/v4l2_capture_delegate.cc
@@ -279,7 +279,7 @@
   // favour mjpeg over raw formats.
   const std::vector<uint32_t>& desired_v4l2_formats =
       GetListOfUsableFourCcs(width > kMjpegWidth || height > kMjpegHeight);
-  std::vector<uint32_t>::const_iterator best = desired_v4l2_formats.end();
+  auto best = desired_v4l2_formats.end();
 
   v4l2_fmtdesc fmtdesc = {};
   fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
diff --git a/media/capture/video/video_capture_system_impl.cc b/media/capture/video/video_capture_system_impl.cc
index 2c41b18..ef82af1 100644
--- a/media/capture/video/video_capture_system_impl.cc
+++ b/media/capture/video/video_capture_system_impl.cc
@@ -51,7 +51,7 @@
   }
   std::sort(formats->begin(), formats->end(), IsCaptureFormatSmaller);
   // Remove duplicates
-  media::VideoCaptureFormats::iterator last =
+  auto last =
       std::unique(formats->begin(), formats->end(), IsCaptureFormatEqual);
   formats->erase(last, formats->end());
 }
@@ -79,7 +79,7 @@
 }
 
 void VideoCaptureSystemImpl::ProcessDeviceInfoRequest() {
-  DeviceEnumQueue::iterator request = device_enum_request_queue_.begin();
+  auto request = device_enum_request_queue_.begin();
   if (request == device_enum_request_queue_.end()) {
     return;
   }
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc
index 9a174f4..e102cd7 100644
--- a/media/cdm/aes_decryptor.cc
+++ b/media/cdm/aes_decryptor.cc
@@ -118,7 +118,7 @@
 void AesDecryptor::SessionIdDecryptionKeyMap::Insert(
     const std::string& session_id,
     std::unique_ptr<DecryptionKey> decryption_key) {
-  KeyList::iterator it = Find(session_id);
+  auto it = Find(session_id);
   if (it != key_list_.end())
     Erase(it);
   key_list_.push_front(std::make_pair(session_id, std::move(decryption_key)));
@@ -126,7 +126,7 @@
 
 void AesDecryptor::SessionIdDecryptionKeyMap::Erase(
     const std::string& session_id) {
-  KeyList::iterator it = Find(session_id);
+  auto it = Find(session_id);
   if (it == key_list_.end())
     return;
   Erase(it);
@@ -134,7 +134,7 @@
 
 AesDecryptor::SessionIdDecryptionKeyMap::KeyList::iterator
 AesDecryptor::SessionIdDecryptionKeyMap::Find(const std::string& session_id) {
-  for (KeyList::iterator it = key_list_.begin(); it != key_list_.end(); ++it) {
+  for (auto it = key_list_.begin(); it != key_list_.end(); ++it) {
     if (it->first == session_id)
       return it;
   }
@@ -308,7 +308,7 @@
   }
 
   bool local_key_added = false;
-  for (KeyIdAndKeyPairs::iterator it = keys.begin(); it != keys.end(); ++it) {
+  for (auto it = keys.begin(); it != keys.end(); ++it) {
     if (it->second.length() !=
         static_cast<size_t>(DecryptConfig::kDecryptionKeySize)) {
       DVLOG(1) << "Invalid key length: " << it->second.length();
@@ -590,7 +590,7 @@
   }
 
   base::AutoLock auto_lock(key_map_lock_);
-  KeyIdToSessionKeysMap::iterator key_id_entry = key_map_.find(key_id);
+  auto key_id_entry = key_map_.find(key_id);
   if (key_id_entry != key_map_.end()) {
     key_id_entry->second->Insert(session_id, std::move(decryption_key));
     return true;
@@ -607,7 +607,7 @@
 AesDecryptor::DecryptionKey* AesDecryptor::GetKey_Locked(
     const std::string& key_id) const {
   key_map_lock_.AssertAcquired();
-  KeyIdToSessionKeysMap::const_iterator key_id_found = key_map_.find(key_id);
+  auto key_id_found = key_map_.find(key_id);
   if (key_id_found == key_map_.end())
     return NULL;
 
@@ -631,13 +631,13 @@
   // Remove all keys associated with |session_id|. Since the data is
   // optimized for access in GetKey_Locked(), we need to look at each entry in
   // |key_map_|.
-  KeyIdToSessionKeysMap::iterator it = key_map_.begin();
+  auto it = key_map_.begin();
   while (it != key_map_.end()) {
     it->second->Erase(session_id);
     if (it->second->Empty()) {
       // Need to get rid of the entry for this key_id. This will mess up the
       // iterator, so we need to increment it first.
-      KeyIdToSessionKeysMap::iterator current = it;
+      auto current = it;
       ++it;
       key_map_.erase(current);
     } else {
diff --git a/media/cdm/library_cdm/clear_key_cdm/cdm_file_io_test.cc b/media/cdm/library_cdm/clear_key_cdm/cdm_file_io_test.cc
index 2485bfe0..df13c7d 100644
--- a/media/cdm/library_cdm/clear_key_cdm/cdm_file_io_test.cc
+++ b/media/cdm/library_cdm/clear_key_cdm/cdm_file_io_test.cc
@@ -639,7 +639,7 @@
     return false;
 
   // If there are multiple results expected, the order does not matter.
-  std::list<TestStep>::iterator iter = test_steps_.begin();
+  auto iter = test_steps_.begin();
   for (; iter != test_steps_.end(); ++iter) {
     if (!IsResult(*iter))
       return false;
diff --git a/media/filters/aom_video_decoder_unittest.cc b/media/filters/aom_video_decoder_unittest.cc
index f48a31f..9f656926 100644
--- a/media/filters/aom_video_decoder_unittest.cc
+++ b/media/filters/aom_video_decoder_unittest.cc
@@ -90,8 +90,8 @@
   // output frames into |output_frames|. Returns the last decode status returned
   // by the decoder.
   DecodeStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
-    for (InputBuffers::const_iterator iter = input_buffers.begin();
-         iter != input_buffers.end(); ++iter) {
+    for (auto iter = input_buffers.begin(); iter != input_buffers.end();
+         ++iter) {
       DecodeStatus status = Decode(*iter);
       switch (status) {
         case DecodeStatus::OK:
diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc
index e93ca4c..cf8f4685 100644
--- a/media/filters/decrypting_audio_decoder.cc
+++ b/media/filters/decrypting_audio_decoder.cc
@@ -348,8 +348,7 @@
 
 void DecryptingAudioDecoder::ProcessDecodedFrames(
     const Decryptor::AudioFrames& frames) {
-  for (Decryptor::AudioFrames::const_iterator iter = frames.begin();
-       iter != frames.end(); ++iter) {
+  for (auto iter = frames.begin(); iter != frames.end(); ++iter) {
     scoped_refptr<AudioBuffer> frame = *iter;
 
     DCHECK(!frame->end_of_stream()) << "EOS frame returned.";
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 16469315..eef8892 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -124,8 +124,7 @@
   // output frames into |output_frames|.
   // Returns the last decode status returned by the decoder.
   DecodeStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
-    for (InputBuffers::const_iterator iter = input_buffers.begin();
-         iter != input_buffers.end();
+    for (auto iter = input_buffers.begin(); iter != input_buffers.end();
          ++iter) {
       DecodeStatus status = Decode(*iter);
       switch (status) {
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 5686bf7b..1399f92 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -379,23 +379,15 @@
     std::move(init_cb_).Run(success);
 }
 
-void GpuVideoDecoder::DestroyPictureBuffers() {
+void GpuVideoDecoder::DestroyPictureBuffers(PictureBufferMap* buffers) {
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
-
-  for (const auto& kv : assigned_picture_buffers_) {
-    int64_t picture_buffer_id = kv.first;
-    PictureBuffer::TextureIds texture_ids = kv.second.client_texture_ids();
-
-    // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since
-    // their textures may still be in use by the user of this GpuVideoDecoder.
-    if (picture_buffers_at_display_.find(picture_buffer_id) ==
-        picture_buffers_at_display_.end()) {
-      for (uint32_t id : texture_ids)
-        factories_->DeleteTexture(id);
-    }
+  for (const auto& kv : *buffers) {
+    for (uint32_t id : kv.second.client_texture_ids())
+      factories_->DeleteTexture(id);
   }
   factories_->ShallowFlushCHROMIUM();
-  assigned_picture_buffers_.clear();
+
+  buffers->clear();
 }
 
 void GpuVideoDecoder::DestroyVDA() {
@@ -403,7 +395,11 @@
 
   vda_.reset();
 
-  DestroyPictureBuffers();
+  // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since
+  // their textures may still be in use by the user of this GpuVideoDecoder.
+  for (const auto& kv : picture_buffers_at_display_)
+    assigned_picture_buffers_.erase(kv.first);
+  DestroyPictureBuffers(&assigned_picture_buffers_);
 }
 
 void GpuVideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
@@ -586,31 +582,32 @@
   DVLOG(3) << "DismissPictureBuffer(" << id << ")";
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
 
-  PictureBufferMap::iterator it = assigned_picture_buffers_.find(id);
+  auto it = assigned_picture_buffers_.find(id);
   if (it == assigned_picture_buffers_.end()) {
     NOTREACHED() << "Missing picture buffer: " << id;
     return;
   }
 
+  PictureBuffer buffer_to_dismiss = it->second;
+  assigned_picture_buffers_.erase(it);
+
   // If it's in |picture_buffers_at_display_|, postpone deletion of it until
   // it's returned to us.
-  if (picture_buffers_at_display_.find(id) ==
-      picture_buffers_at_display_.end()) {
-    for (const auto texture_id : (it->second).client_texture_ids())
-      factories_->DeleteTexture(texture_id);
-  }
+  if (picture_buffers_at_display_.count(id))
+    return;
 
-  assigned_picture_buffers_.erase(it);
+  // Otherwise, we can delete the texture immediately.
+  for (uint32_t id : buffer_to_dismiss.client_texture_ids())
+    factories_->DeleteTexture(id);
+  CHECK_GT(available_pictures_, 0);
   --available_pictures_;
-  CHECK_GE(available_pictures_, 0);
 }
 
 void GpuVideoDecoder::PictureReady(const media::Picture& picture) {
   DVLOG(3) << "PictureReady()";
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
 
-  PictureBufferMap::iterator it =
-      assigned_picture_buffers_.find(picture.picture_buffer_id());
+  auto it = assigned_picture_buffers_.find(picture.picture_buffer_id());
   if (it == assigned_picture_buffers_.end()) {
     DLOG(ERROR) << "Missing picture buffer: " << picture.picture_buffer_id();
     NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
@@ -685,13 +682,14 @@
   if (requires_texture_copy_)
     frame->metadata()->SetBoolean(VideoFrameMetadata::COPY_REQUIRED, true);
 
-  if (picture_buffers_at_display_.find(picture.picture_buffer_id()) ==
-      picture_buffers_at_display_.end()) {
-    --available_pictures_;
-    CHECK_GE(available_pictures_, 0);
-  }
-  picture_buffers_at_display_.insert(
-      std::make_pair(picture.picture_buffer_id(), pb.client_texture_ids()));
+  CHECK_GT(available_pictures_, 0);
+  --available_pictures_;
+
+  bool inserted = picture_buffers_at_display_
+                      .insert(std::make_pair(picture.picture_buffer_id(),
+                                             pb.client_texture_ids()))
+                      .second;
+  DCHECK(inserted);
 
   DeliverFrame(frame);
 }
@@ -736,23 +734,22 @@
   DVLOG(3) << "ReusePictureBuffer(" << picture_buffer_id << ")";
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
 
-  auto iter_range = picture_buffers_at_display_.equal_range(picture_buffer_id);
-  DCHECK(iter_range.first != iter_range.second);
-  bool only_one_element = (std::next(iter_range.first) == iter_range.second);
-  PictureBuffer::TextureIds ids = iter_range.first->second;
-  picture_buffers_at_display_.erase(iter_range.first);
+  DCHECK(!picture_buffers_at_display_.empty());
+  PictureBufferTextureMap::iterator display_iterator =
+      picture_buffers_at_display_.find(picture_buffer_id);
+  PictureBuffer::TextureIds ids = display_iterator->second;
+  DCHECK(display_iterator != picture_buffers_at_display_.end());
+  picture_buffers_at_display_.erase(display_iterator);
 
-  if (only_one_element) {
-    if (assigned_picture_buffers_.find(picture_buffer_id) ==
-        assigned_picture_buffers_.end()) {
-      // This picture was dismissed while in display, so we postponed deletion.
-      for (const auto id : ids)
-        factories_->DeleteTexture(id);
-      return;
-    }
-    ++available_pictures_;
+  if (!assigned_picture_buffers_.count(picture_buffer_id)) {
+    // This picture was dismissed while in display, so we postponed deletion.
+    for (uint32_t id : ids)
+      factories_->DeleteTexture(id);
+    return;
   }
 
+  ++available_pictures_;
+
   // DestroyVDA() might already have been called.
   if (vda_)
     vda_->ReusePictureBuffer(picture_buffer_id);
@@ -801,8 +798,7 @@
   DVLOG(3) << "NotifyEndOfBitstreamBuffer(" << id << ")";
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
 
-  std::map<int32_t, PendingDecoderBuffer>::iterator it =
-      bitstream_buffers_in_decoder_.find(id);
+  auto it = bitstream_buffers_in_decoder_.find(id);
   if (it == bitstream_buffers_in_decoder_.end()) {
     NotifyError(VideoDecodeAccelerator::PLATFORM_FAILURE);
     NOTREACHED() << "Missing bitstream buffer: " << id;
@@ -829,8 +825,7 @@
     std::move(request_overlay_info_cb_).Run(false, ProvideOverlayInfoCB());
   }
 
-  for (std::map<int32_t, PendingDecoderBuffer>::iterator it =
-           bitstream_buffers_in_decoder_.begin();
+  for (auto it = bitstream_buffers_in_decoder_.begin();
        it != bitstream_buffers_in_decoder_.end(); ++it) {
     it->second.done_cb.Run(DecodeStatus::ABORTED);
   }
diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h
index 5fe6cfe..494cc02 100644
--- a/media/filters/gpu_video_decoder.h
+++ b/media/filters/gpu_video_decoder.h
@@ -127,9 +127,8 @@
   void PutSharedMemory(std::unique_ptr<base::SharedMemory> shm_buffer,
                        int32_t last_bitstream_buffer_id);
 
-  // Destroy all the assigned picture buffers and delete their textures, but
-  // skip the textures of the buffers which is still at display.
-  void DestroyPictureBuffers();
+  // Destroy all PictureBuffers in |buffers|, and delete their textures.
+  void DestroyPictureBuffers(PictureBufferMap* buffers);
 
   // Returns true if the video decoder with |capabilities| can support
   // |profile|, |coded_size|, and |is_encrypted|.
@@ -208,12 +207,11 @@
   PictureBufferMap assigned_picture_buffers_;
   // PictureBuffers given to us by VDA via PictureReady, which we sent forward
   // as VideoFrames to be rendered via decode_cb_, and which will be returned
-  // to us via ReusePictureBuffer. Note that a picture buffer might be sent from
-  // VDA multiple times. Therefore we use multimap to track the number of times
-  // we passed the picture buffer for display.
-  std::multimap<int32_t /* picture_buffer_id */,
-                PictureBuffer::TextureIds /* texture_id */>
-      picture_buffers_at_display_;
+  // to us via ReusePictureBuffer.
+  typedef std::map<int32_t /* picture_buffer_id */,
+                   PictureBuffer::TextureIds /* texture_id */>
+      PictureBufferTextureMap;
+  PictureBufferTextureMap picture_buffers_at_display_;
 
   struct BufferData {
     BufferData(int32_t bbid,
diff --git a/media/filters/source_buffer_range_by_dts.cc b/media/filters/source_buffer_range_by_dts.cc
index 3d11c1c..4b3fe7f 100644
--- a/media/filters/source_buffer_range_by_dts.cc
+++ b/media/filters/source_buffer_range_by_dts.cc
@@ -144,7 +144,7 @@
   DCHECK(CanSeekTo(timestamp));
   DCHECK(!keyframe_map_.empty());
 
-  KeyframeMap::const_iterator result = GetFirstKeyframeAtOrBefore(timestamp);
+  auto result = GetFirstKeyframeAtOrBefore(timestamp);
   next_buffer_index_ = result->second - keyframe_map_index_base_;
   CHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size()))
       << next_buffer_index_ << ", size = " << buffers_.size();
@@ -154,7 +154,7 @@
   DCHECK(CanSeekTo(timestamp));
   DCHECK(!keyframe_map_.empty());
 
-  KeyframeMap::const_iterator result = GetFirstKeyframeAtOrBefore(timestamp);
+  auto result = GetFirstKeyframeAtOrBefore(timestamp);
   CHECK(result != keyframe_map_.end());
   size_t buffer_index = result->second - keyframe_map_index_base_;
   CHECK_LT(buffer_index, buffers_.size())
@@ -173,7 +173,7 @@
   if (start == end)
     return true;
 
-  KeyframeMap::const_iterator result = GetFirstKeyframeAtOrBefore(start);
+  auto result = GetFirstKeyframeAtOrBefore(start);
   CHECK(result != keyframe_map_.end());
   size_t buffer_index = result->second - keyframe_map_index_base_;
   CHECK_LT(buffer_index, buffers_.size())
@@ -196,8 +196,7 @@
   CHECK(!buffers_.empty());
 
   // Find the first keyframe at or after |timestamp|.
-  KeyframeMap::const_iterator new_beginning_keyframe =
-      GetFirstKeyframeAt(timestamp, false);
+  auto new_beginning_keyframe = GetFirstKeyframeAt(timestamp, false);
 
   // If there is no keyframe after |timestamp|, we can't split the range.
   if (new_beginning_keyframe == keyframe_map_.end()) {
@@ -348,19 +347,18 @@
     DecodeTimestamp* removal_end_timestamp) const {
   size_t bytes_removed = 0;
 
-  KeyframeMap::const_iterator gop_itr =
-      GetFirstKeyframeAt(start_timestamp, false);
+  auto gop_itr = GetFirstKeyframeAt(start_timestamp, false);
   if (gop_itr == keyframe_map_.end())
     return 0;
   int keyframe_index = gop_itr->second - keyframe_map_index_base_;
   BufferQueue::const_iterator buffer_itr = buffers_.begin() + keyframe_index;
-  KeyframeMap::const_iterator gop_end = keyframe_map_.end();
+  auto gop_end = keyframe_map_.end();
   if (end_timestamp < GetBufferedEndTimestamp())
     gop_end = GetFirstKeyframeAtOrBefore(end_timestamp);
 
   // Check if the removal range is within a GOP and skip the loop if so.
   // [keyframe]...[start_timestamp]...[end_timestamp]...[keyframe]
-  KeyframeMap::const_iterator gop_itr_prev = gop_itr;
+  auto gop_itr_prev = gop_itr;
   if (gop_itr_prev != keyframe_map_.begin() && --gop_itr_prev == gop_end)
     gop_end = gop_itr;
 
@@ -392,7 +390,7 @@
   if (keyframe_map_.size() == 1u)
     return (GetBufferedEndTimestamp() <= media_time);
 
-  KeyframeMap::const_iterator second_gop = keyframe_map_.begin();
+  auto second_gop = keyframe_map_.begin();
   ++second_gop;
   return second_gop->first <= media_time;
 }
@@ -405,7 +403,7 @@
   if (keyframe_map_.size() == 1u)
     return true;
 
-  KeyframeMap::const_iterator second_gop = keyframe_map_.begin();
+  auto second_gop = keyframe_map_.begin();
   ++second_gop;
   return next_buffer_index_ < second_gop->second - keyframe_map_index_base_;
 }
@@ -418,7 +416,7 @@
   if (keyframe_map_.size() == 1u)
     return true;
 
-  KeyframeMap::const_iterator last_gop = keyframe_map_.end();
+  auto last_gop = keyframe_map_.end();
   --last_gop;
   return last_gop->second - keyframe_map_index_base_ <= next_buffer_index_;
 }
@@ -490,7 +488,7 @@
     return timestamp;
   }
 
-  KeyframeMap::const_iterator key_iter = GetFirstKeyframeAtOrBefore(timestamp);
+  auto key_iter = GetFirstKeyframeAtOrBefore(timestamp);
   DCHECK(key_iter != keyframe_map_.end())
       << "BelongsToRange() semantics failed.";
   DCHECK(key_iter->first <= timestamp);
@@ -523,7 +521,7 @@
   if (timestamp < GetStartTimestamp() || timestamp >= GetBufferedEndTimestamp())
     return kNoDecodeTimestamp();
 
-  KeyframeMap::const_iterator itr = GetFirstKeyframeAt(timestamp, false);
+  auto itr = GetFirstKeyframeAt(timestamp, false);
   if (itr == keyframe_map_.end())
     return kNoDecodeTimestamp();
 
@@ -603,7 +601,7 @@
 SourceBufferRangeByDts::KeyframeMap::const_iterator
 SourceBufferRangeByDts::GetFirstKeyframeAtOrBefore(
     DecodeTimestamp timestamp) const {
-  KeyframeMap::const_iterator result = keyframe_map_.lower_bound(timestamp);
+  auto result = keyframe_map_.lower_bound(timestamp);
   // lower_bound() returns the first element >= |timestamp|, so we want the
   // previous element if it did not return the element exactly equal to
   // |timestamp|.
diff --git a/media/filters/source_buffer_range_by_pts.cc b/media/filters/source_buffer_range_by_pts.cc
index 1ded05f..3226bc31 100644
--- a/media/filters/source_buffer_range_by_pts.cc
+++ b/media/filters/source_buffer_range_by_pts.cc
@@ -146,7 +146,7 @@
   DCHECK(CanSeekTo(timestamp));
   DCHECK(!keyframe_map_.empty());
 
-  KeyframeMap::const_iterator result = GetFirstKeyframeAtOrBefore(timestamp);
+  auto result = GetFirstKeyframeAtOrBefore(timestamp);
   next_buffer_index_ = result->second - keyframe_map_index_base_;
   CHECK_LT(next_buffer_index_, static_cast<int>(buffers_.size()))
       << next_buffer_index_ << ", size = " << buffers_.size();
@@ -169,7 +169,7 @@
   DCHECK(CanSeekTo(timestamp));
   DCHECK(!keyframe_map_.empty());
 
-  KeyframeMap::const_iterator result = GetFirstKeyframeAtOrBefore(timestamp);
+  auto result = GetFirstKeyframeAtOrBefore(timestamp);
   CHECK(result != keyframe_map_.end());
   size_t buffer_index = result->second - keyframe_map_index_base_;
   CHECK_LT(buffer_index, buffers_.size())
@@ -191,7 +191,7 @@
   if (start == end)
     return true;
 
-  KeyframeMap::const_iterator result = GetFirstKeyframeAtOrBefore(start);
+  auto result = GetFirstKeyframeAtOrBefore(start);
   CHECK(result != keyframe_map_.end());
   size_t buffer_index = result->second - keyframe_map_index_base_;
   CHECK_LT(buffer_index, buffers_.size())
@@ -217,8 +217,7 @@
   CHECK(!buffers_.empty());
 
   // Find the first keyframe at or after |timestamp|.
-  KeyframeMap::const_iterator new_beginning_keyframe =
-      GetFirstKeyframeAt(timestamp, false);
+  auto new_beginning_keyframe = GetFirstKeyframeAt(timestamp, false);
 
   // If there is no keyframe at or after |timestamp|, we can't split the range.
   if (new_beginning_keyframe == keyframe_map_.end())
@@ -378,19 +377,18 @@
 
   size_t bytes_removed = 0;
 
-  KeyframeMap::const_iterator gop_itr =
-      GetFirstKeyframeAt(start_timestamp, false);
+  auto gop_itr = GetFirstKeyframeAt(start_timestamp, false);
   if (gop_itr == keyframe_map_.end())
     return 0;
   int keyframe_index = gop_itr->second - keyframe_map_index_base_;
   BufferQueue::const_iterator buffer_itr = buffers_.begin() + keyframe_index;
-  KeyframeMap::const_iterator gop_end = keyframe_map_.end();
+  auto gop_end = keyframe_map_.end();
   if (end_timestamp < GetBufferedEndTimestamp())
     gop_end = GetFirstKeyframeAtOrBefore(end_timestamp);
 
   // Check if the removal range is within a GOP and skip the loop if so.
   // [keyframe]...[start_timestamp]...[end_timestamp]...[keyframe]
-  KeyframeMap::const_iterator gop_itr_prev = gop_itr;
+  auto gop_itr_prev = gop_itr;
   if (gop_itr_prev != keyframe_map_.begin() && --gop_itr_prev == gop_end)
     gop_end = gop_itr;
 
@@ -425,7 +423,7 @@
   if (keyframe_map_.size() == 1u)
     return (GetBufferedEndTimestamp() <= media_time);
 
-  KeyframeMap::const_iterator second_gop = keyframe_map_.begin();
+  auto second_gop = keyframe_map_.begin();
   ++second_gop;
   return second_gop->first <= media_time;
 }
@@ -441,7 +439,7 @@
   if (keyframe_map_.size() == 1u)
     return true;
 
-  KeyframeMap::const_iterator second_gop = keyframe_map_.begin();
+  auto second_gop = keyframe_map_.begin();
   ++second_gop;
   return next_buffer_index_ < second_gop->second - keyframe_map_index_base_;
 }
@@ -457,7 +455,7 @@
   if (keyframe_map_.size() == 1u)
     return true;
 
-  KeyframeMap::const_iterator last_gop = keyframe_map_.end();
+  auto last_gop = keyframe_map_.end();
   --last_gop;
   return last_gop->second - keyframe_map_index_base_ <= next_buffer_index_;
 }
@@ -546,7 +544,7 @@
     return timestamp;
   }
 
-  KeyframeMap::const_iterator key_iter = GetFirstKeyframeAtOrBefore(timestamp);
+  auto key_iter = GetFirstKeyframeAtOrBefore(timestamp);
   DCHECK(key_iter != keyframe_map_.end())
       << "BelongsToRange() semantics failed.";
   DCHECK(key_iter->first <= timestamp);
@@ -583,7 +581,7 @@
   if (timestamp < GetStartTimestamp() || timestamp >= GetBufferedEndTimestamp())
     return kNoTimestamp;
 
-  KeyframeMap::const_iterator itr = GetFirstKeyframeAt(timestamp, false);
+  auto itr = GetFirstKeyframeAt(timestamp, false);
   if (itr == keyframe_map_.end())
     return kNoTimestamp;
 
@@ -672,7 +670,7 @@
 
   // Find the GOP containing |timestamp| (or trivial buffers_.size() if none
   // contain |timestamp|).
-  KeyframeMap::const_iterator gop_iter = GetFirstKeyframeAtOrBefore(timestamp);
+  auto gop_iter = GetFirstKeyframeAtOrBefore(timestamp);
   if (gop_iter == keyframe_map_.end())
     return buffers_.size();
 
@@ -731,7 +729,7 @@
   DVLOG(1) << __func__;
   DVLOG(4) << ToStringForDebugging();
 
-  KeyframeMap::const_iterator result = keyframe_map_.lower_bound(timestamp);
+  auto result = keyframe_map_.lower_bound(timestamp);
   // lower_bound() returns the first element >= |timestamp|, so we want the
   // previous element if it did not return the element exactly equal to
   // |timestamp|.
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc
index 8b017311..9a9c7070 100644
--- a/media/filters/source_buffer_stream.cc
+++ b/media/filters/source_buffer_stream.cc
@@ -265,7 +265,7 @@
   coded_frame_group_start_time_ = coded_frame_group_start_time;
   new_coded_frame_group_ = true;
 
-  typename RangeList::iterator last_range = range_for_next_append_;
+  auto last_range = range_for_next_append_;
   range_for_next_append_ = FindExistingRangeFor(coded_frame_group_start_time);
 
   // Only reset |last_appended_buffer_timestamp_| if this new coded frame group
@@ -632,7 +632,7 @@
   // Doing this upfront simplifies decisions about range_for_next_append_ below.
   UpdateLastAppendStateForRemove(start, end, exclude_start);
 
-  typename RangeList::iterator itr = ranges_.begin();
+  auto itr = ranges_.begin();
   while (itr != ranges_.end()) {
     RangeClass* range = itr->get();
     if (RangeGetStartTimestamp(range) >= end)
@@ -790,8 +790,7 @@
 
 template <typename RangeClass>
 bool SourceBufferStream<RangeClass>::OnlySelectedRangeIsSeeked() const {
-  for (typename RangeList::const_iterator itr = ranges_.begin();
-       itr != ranges_.end(); ++itr) {
+  for (auto itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
     if ((*itr)->HasNextBufferPosition() && itr->get() != selected_range_)
       return false;
   }
@@ -1088,7 +1087,7 @@
 
   size_t bytes_freed = 0;
 
-  for (typename RangeList::iterator itr = ranges_.begin();
+  for (auto itr = ranges_.begin();
        itr != ranges_.end() && bytes_freed < total_bytes_to_free; ++itr) {
     RangeClass* range = itr->get();
     if (RangeGetStartTimestamp(range) >= end_timestamp)
@@ -1199,7 +1198,7 @@
     // Merging is necessary if there were no buffers (or very few buffers)
     // deleted after creating that added range.
     if (range_for_next_append_ != ranges_.begin()) {
-      typename RangeList::iterator range_before_next = range_for_next_append_;
+      auto range_before_next = range_for_next_append_;
       --range_before_next;
       MergeWithNextRangeIfNecessary(range_before_next);
     }
@@ -1218,7 +1217,7 @@
   const base::TimeDelta splice_timestamp = new_buffers.front()->timestamp();
   const DecodeTimestamp splice_dts =
       DecodeTimestamp::FromPresentationTime(splice_timestamp);
-  typename RangeList::iterator range_itr = FindExistingRangeFor(splice_dts);
+  auto range_itr = FindExistingRangeFor(splice_dts);
   if (range_itr == ranges_.end()) {
     DVLOG(3) << __func__ << " No splice trimming. No range overlap at time "
              << splice_timestamp.InMicroseconds();
@@ -1566,7 +1565,7 @@
   DVLOG(1) << __func__ << " " << GetStreamTypeName()
            << ": Before: ranges_=" << RangesToString<RangeClass>(ranges_);
 
-  typename RangeList::iterator range_itr = ranges_.begin();
+  auto range_itr = ranges_.begin();
 
   while (range_itr != ranges_.end()) {
     const size_t old_ranges_size = ranges_.size();
@@ -1600,7 +1599,7 @@
 
   DecodeTimestamp seek_dts = DecodeTimestamp::FromPresentationTime(timestamp);
 
-  typename RangeList::iterator itr = ranges_.end();
+  auto itr = ranges_.end();
   for (itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
     if (RangeCanSeekTo(itr->get(), seek_dts))
       break;
@@ -1816,8 +1815,7 @@
 typename SourceBufferStream<RangeClass>::RangeList::iterator
 SourceBufferStream<RangeClass>::FindExistingRangeFor(
     DecodeTimestamp start_timestamp) {
-  for (typename RangeList::iterator itr = ranges_.begin(); itr != ranges_.end();
-       ++itr) {
+  for (auto itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
     if (RangeBelongsToRange(itr->get(), start_timestamp))
       return itr;
   }
@@ -1829,7 +1827,7 @@
 SourceBufferStream<RangeClass>::AddToRanges(
     std::unique_ptr<RangeClass> new_range) {
   DecodeTimestamp start_timestamp = RangeGetStartTimestamp(new_range.get());
-  typename RangeList::iterator itr = ranges_.end();
+  auto itr = ranges_.end();
   for (itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
     if (RangeGetStartTimestamp(itr->get()) > start_timestamp)
       break;
@@ -1841,7 +1839,7 @@
 typename SourceBufferStream<RangeClass>::RangeList::iterator
 SourceBufferStream<RangeClass>::GetSelectedRangeItr() {
   DCHECK(selected_range_);
-  typename RangeList::iterator itr = ranges_.end();
+  auto itr = ranges_.end();
   for (itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
     if (itr->get() == selected_range_)
       break;
@@ -1874,8 +1872,7 @@
 Ranges<base::TimeDelta> SourceBufferStream<RangeClass>::GetBufferedTime()
     const {
   Ranges<base::TimeDelta> ranges;
-  for (typename RangeList::const_iterator itr = ranges_.begin();
-       itr != ranges_.end(); ++itr) {
+  for (auto itr = ranges_.begin(); itr != ranges_.end(); ++itr) {
     ranges.Add(RangeGetStartTimestamp(itr->get()).ToPresentationTime(),
                RangeGetBufferedEndTimestamp(itr->get()).ToPresentationTime());
   }
@@ -2112,7 +2109,7 @@
   DCHECK(start_timestamp != kNoDecodeTimestamp());
   DCHECK(start_timestamp >= DecodeTimestamp());
 
-  typename RangeList::iterator itr = ranges_.begin();
+  auto itr = ranges_.begin();
 
   // When checking a range to see if it has or begins soon enough after
   // |start_timestamp|, use the fudge room to determine "soon enough".
@@ -2150,7 +2147,7 @@
     const DecodeTimestamp timestamp) {
   DCHECK(timestamp != kNoDecodeTimestamp());
 
-  typename RangeList::iterator itr = FindExistingRangeFor(timestamp);
+  auto itr = FindExistingRangeFor(timestamp);
 
   if (itr == ranges_.end())
     return kNoDecodeTimestamp();
diff --git a/media/filters/vpx_video_decoder_unittest.cc b/media/filters/vpx_video_decoder_unittest.cc
index 611b6cc..1ab0b1a7 100644
--- a/media/filters/vpx_video_decoder_unittest.cc
+++ b/media/filters/vpx_video_decoder_unittest.cc
@@ -85,8 +85,8 @@
   // output frames into |output_frames|.
   // Returns the last decode status returned by the decoder.
   DecodeStatus DecodeMultipleFrames(const InputBuffers& input_buffers) {
-    for (InputBuffers::const_iterator iter = input_buffers.begin();
-         iter != input_buffers.end(); ++iter) {
+    for (auto iter = input_buffers.begin(); iter != input_buffers.end();
+         ++iter) {
       DecodeStatus status = Decode(*iter);
       switch (status) {
         case DecodeStatus::OK:
diff --git a/media/formats/mp4/box_definitions.cc b/media/formats/mp4/box_definitions.cc
index 45a324a..7876571 100644
--- a/media/formats/mp4/box_definitions.cc
+++ b/media/formats/mp4/box_definitions.cc
@@ -521,8 +521,7 @@
   RCHECK(count <= edits.max_size());
   edits.resize(count);
 
-  for (std::vector<EditListEntry>::iterator edit = edits.begin();
-       edit != edits.end(); ++edit) {
+  for (auto edit = edits.begin(); edit != edits.end(); ++edit) {
     if (reader->version() == 1) {
       RCHECK(reader->Read8(&edit->segment_duration) &&
              reader->Read8s(&edit->media_time));
diff --git a/media/formats/mp4/box_reader.cc b/media/formats/mp4/box_reader.cc
index cbcd48c..131ae34 100644
--- a/media/formats/mp4/box_reader.cc
+++ b/media/formats/mp4/box_reader.cc
@@ -106,8 +106,7 @@
 
 BoxReader::~BoxReader() {
   if (scanned_ && !children_.empty()) {
-    for (ChildMap::iterator itr = children_.begin();
-         itr != children_.end(); ++itr) {
+    for (auto itr = children_.begin(); itr != children_.end(); ++itr) {
       DVLOG(1) << "Skipping unknown box: " << FourCCToString(itr->first);
     }
   }
@@ -223,7 +222,7 @@
   DCHECK(scanned_);
   FourCC child_type = child->BoxType();
 
-  ChildMap::iterator itr = children_.find(child_type);
+  auto itr = children_.find(child_type);
   RCHECK(itr != children_.end());
   DVLOG(2) << "Found a " << FourCCToString(child_type) << " box.";
   RCHECK(child->Parse(&itr->second));
diff --git a/media/formats/mp4/track_run_iterator.cc b/media/formats/mp4/track_run_iterator.cc
index e27c7a4..ffd7113 100644
--- a/media/formats/mp4/track_run_iterator.cc
+++ b/media/formats/mp4/track_run_iterator.cc
@@ -619,7 +619,7 @@
       offset = std::min(offset, aux_info_offset());
   }
   if (run_itr_ != runs_.end()) {
-    std::vector<TrackRunInfo>::const_iterator next_run = run_itr_ + 1;
+    auto next_run = run_itr_ + 1;
     if (next_run != runs_.end()) {
       offset = std::min(offset, next_run->sample_start_offset);
       if (next_run->aux_info_total_size)
diff --git a/media/formats/webm/tracks_builder.cc b/media/formats/webm/tracks_builder.cc
index 7549e12..60c0abb 100644
--- a/media/formats/webm/tracks_builder.cc
+++ b/media/formats/webm/tracks_builder.cc
@@ -224,8 +224,7 @@
 int TracksBuilder::GetTracksPayloadSize() const {
   int payload_size = 0;
 
-  for (TrackList::const_iterator itr = tracks_.begin();
-       itr != tracks_.end(); ++itr) {
+  for (auto itr = tracks_.begin(); itr != tracks_.end(); ++itr) {
     payload_size += itr->GetSize();
   }
 
@@ -235,8 +234,7 @@
 void TracksBuilder::WriteTracks(uint8_t* buf, int buf_size) const {
   WriteMasterElement(&buf, &buf_size, kWebMIdTracks, GetTracksPayloadSize());
 
-  for (TrackList::const_iterator itr = tracks_.begin();
-       itr != tracks_.end(); ++itr) {
+  for (auto itr = tracks_.begin(); itr != tracks_.end(); ++itr) {
     itr->Write(&buf, &buf_size);
   }
 }
diff --git a/media/formats/webm/webm_cluster_parser.cc b/media/formats/webm/webm_cluster_parser.cc
index 3b5ba5b7..f4aa78c7 100644
--- a/media/formats/webm/webm_cluster_parser.cc
+++ b/media/formats/webm/webm_cluster_parser.cc
@@ -64,9 +64,7 @@
              media_log),
       ready_buffer_upper_bound_(kNoDecodeTimestamp()),
       media_log_(media_log) {
-  for (WebMTracksParser::TextTracks::const_iterator it = text_tracks.begin();
-       it != text_tracks.end();
-       ++it) {
+  for (auto it = text_tracks.begin(); it != text_tracks.end(); ++it) {
     text_track_map_.insert(std::make_pair(
         it->first,
         Track(it->first, TrackType::TEXT, kNoTimestamp, media_log_)));
@@ -818,18 +816,14 @@
 
 void WebMClusterParser::ClearTextTrackReadyBuffers() {
   text_buffers_map_.clear();
-  for (TextTrackMap::iterator it = text_track_map_.begin();
-       it != text_track_map_.end();
-       ++it) {
+  for (auto it = text_track_map_.begin(); it != text_track_map_.end(); ++it) {
     it->second.ClearReadyBuffers();
   }
 }
 
 void WebMClusterParser::ResetTextTracks() {
   ClearTextTrackReadyBuffers();
-  for (TextTrackMap::iterator it = text_track_map_.begin();
-       it != text_track_map_.end();
-       ++it) {
+  for (auto it = text_track_map_.begin(); it != text_track_map_.end(); ++it) {
     it->second.Reset();
   }
 }
@@ -858,8 +852,7 @@
   // Prepare each track's ready buffers for retrieval.
   audio_.ExtractReadyBuffers(ready_buffer_upper_bound_);
   video_.ExtractReadyBuffers(ready_buffer_upper_bound_);
-  for (TextTrackMap::iterator itr = text_track_map_.begin();
-       itr != text_track_map_.end();
+  for (auto itr = text_track_map_.begin(); itr != text_track_map_.end();
        ++itr) {
     itr->second.ExtractReadyBuffers(ready_buffer_upper_bound_);
   }
diff --git a/media/formats/webm/webm_cluster_parser_unittest.cc b/media/formats/webm/webm_cluster_parser_unittest.cc
index b605117..7ce98a5 100644
--- a/media/formats/webm/webm_cluster_parser_unittest.cc
+++ b/media/formats/webm/webm_cluster_parser_unittest.cc
@@ -699,10 +699,7 @@
 
   const WebMClusterParser::TextBufferQueueMap& text_map =
       parser_->GetTextBuffers();
-  for (WebMClusterParser::TextBufferQueueMap::const_iterator itr =
-           text_map.begin();
-       itr != text_map.end();
-       ++itr) {
+  for (auto itr = text_map.begin(); itr != text_map.end(); ++itr) {
     const TextTracks::const_iterator find_result =
         text_tracks.find(itr->first);
     ASSERT_TRUE(find_result != text_tracks.end());
diff --git a/media/gpu/h264_decoder.cc b/media/gpu/h264_decoder.cc
index ed0290b..fb3ceb9 100644
--- a/media/gpu/h264_decoder.cc
+++ b/media/gpu/h264_decoder.cc
@@ -922,7 +922,7 @@
   // in DPB afterwards would at least be equal to max_num_reorder_frames.
   // If the outputted picture is not a reference picture, it doesn't have
   // to remain in the DPB and can be removed.
-  H264Picture::Vector::iterator output_candidate = not_outputted.begin();
+  auto output_candidate = not_outputted.begin();
   size_t num_remaining = not_outputted.size();
   while (num_remaining > max_num_reorder_frames_ ||
          // If the condition below is used, this is an invalid stream. We should
diff --git a/media/gpu/h264_dpb.cc b/media/gpu/h264_dpb.cc
index 92c7c1d..85f87b44 100644
--- a/media/gpu/h264_dpb.cc
+++ b/media/gpu/h264_dpb.cc
@@ -77,8 +77,7 @@
 }
 
 void H264DPB::DeleteByPOC(int poc) {
-  for (H264Picture::Vector::iterator it = pics_.begin(); it != pics_.end();
-       ++it) {
+  for (auto it = pics_.begin(); it != pics_.end(); ++it) {
     if ((*it)->pic_order_cnt == poc) {
       pics_.erase(it);
       UpdatePicPositions();
@@ -89,7 +88,7 @@
 }
 
 void H264DPB::DeleteUnused() {
-  for (H264Picture::Vector::iterator it = pics_.begin(); it != pics_.end();) {
+  for (auto it = pics_.begin(); it != pics_.end();) {
     if ((*it)->outputted && !(*it)->ref)
       it = pics_.erase(it);
     else
diff --git a/media/gpu/ipc/service/picture_buffer_manager.cc b/media/gpu/ipc/service/picture_buffer_manager.cc
index 1aab5d8..17e88ba 100644
--- a/media/gpu/ipc/service/picture_buffer_manager.cc
+++ b/media/gpu/ipc/service/picture_buffer_manager.cc
@@ -57,9 +57,7 @@
     // Predict that the VDA can output a picture if at least one picture buffer
     // is not in use as an output.
     for (const auto& it : picture_buffers_) {
-      const auto& state = it.second.state;
-      if (std::find(state.begin(), state.end(), PictureBufferState::OUTPUT) ==
-          state.end())
+      if (it.second.state != PictureBufferState::OUTPUT)
         return true;
     }
 
@@ -89,7 +87,8 @@
     std::vector<PictureBuffer> picture_buffers;
     for (uint32_t i = 0; i < count; i++) {
       PictureBuffer::TextureIds service_ids;
-      PictureBufferData picture_data = {pixel_format, texture_size};
+      PictureBufferData picture_data = {PictureBufferState::AVAILABLE,
+                                        pixel_format, texture_size};
 
       for (uint32_t j = 0; j < planes; j++) {
         // Create a texture for this plane.
@@ -146,13 +145,12 @@
       return false;
     }
 
-    bool is_available = it->second.IsAvailable();
+    bool is_available = it->second.state == PictureBufferState::AVAILABLE;
 
     // Destroy the picture buffer data.
     picture_buffers_.erase(it);
 
-    // If the picture was not bound to any VideoFrame, we can destroy its
-    // textures immediately.
+    // If the picture was available, we can destroy its textures immediately.
     if (is_available) {
       gpu_task_runner_->PostTask(
           FROM_HERE,
@@ -185,6 +183,12 @@
     }
 
     PictureBufferData& picture_buffer_data = it->second;
+    if (picture_buffer_data.state != PictureBufferState::AVAILABLE) {
+      DLOG(ERROR) << "Picture buffer " << picture_buffer_id
+                  << " is not available";
+      return nullptr;
+    }
+
     // Ensure that the picture buffer is large enough.
     if (!gfx::Rect(picture_buffer_data.texture_size).Contains(visible_rect)) {
       DLOG(WARNING) << "visible_rect " << visible_rect.ToString()
@@ -197,7 +201,7 @@
     }
 
     // Mark the picture as an output.
-    picture_buffer_data.state.push_back(PictureBufferState::OUTPUT);
+    picture_buffer_data.state = PictureBufferState::OUTPUT;
 
     // Create and return a VideoFrame for the picture buffer.
     scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTextures(
@@ -230,12 +234,8 @@
     // If the picture buffer is still assigned, mark it as unreleased.
     const auto& it = picture_buffers_.find(picture_buffer_id);
     if (it != picture_buffers_.end()) {
-      auto& state = it->second.state;
-      auto state_it =
-          std::find(state.begin(), state.end(), PictureBufferState::OUTPUT);
-      if (state_it != state.end())
-        state.erase(state_it);
-      state.push_back(PictureBufferState::WAITING_FOR_SYNCTOKEN);
+      DCHECK_EQ(it->second.state, PictureBufferState::OUTPUT);
+      it->second.state = PictureBufferState::WAITING_FOR_SYNCTOKEN;
     }
 
     // Wait for the SyncToken release.
@@ -259,11 +259,8 @@
       base::AutoLock lock(picture_buffers_lock_);
       const auto& it = picture_buffers_.find(picture_buffer_id);
       if (it != picture_buffers_.end()) {
-        auto& state = it->second.state;
-        auto state_it = std::find(state.begin(), state.end(),
-                                  PictureBufferState::WAITING_FOR_SYNCTOKEN);
-        if (state_it != state.end())
-          state.erase(state_it);
+        DCHECK_EQ(it->second.state, PictureBufferState::WAITING_FOR_SYNCTOKEN);
+        it->second.state = PictureBufferState::AVAILABLE;
         is_assigned = true;
       }
     }
@@ -305,22 +302,18 @@
 
   base::Lock picture_buffers_lock_;
   enum class PictureBufferState {
+    // Available for use by the VDA.
+    AVAILABLE,
     // Output by the VDA, still bound to a VideoFrame.
     OUTPUT,
     // Waiting on a SyncToken before being reused.
     WAITING_FOR_SYNCTOKEN,
   };
   struct PictureBufferData {
+    PictureBufferState state;
     VideoPixelFormat pixel_format;
     gfx::Size texture_size;
-    // The picture buffer might be sent from VDA multiple times. Therefore we
-    // use vector to track the status. The state is empty when the picture
-    // buffer is not bound to any VideoFrame.
-    std::vector<PictureBufferState> state;
     gpu::MailboxHolder mailbox_holders[VideoFrame::kMaxPlanes];
-
-    // Available for use by the VDA.
-    bool IsAvailable() const { return state.empty(); }
   };
   // Pictures buffers that are assigned to the VDA.
   std::map<int32_t, PictureBufferData> picture_buffers_;
diff --git a/media/gpu/ipc/service/picture_buffer_manager_unittest.cc b/media/gpu/ipc/service/picture_buffer_manager_unittest.cc
index df51373..1db8cc7f 100644
--- a/media/gpu/ipc/service/picture_buffer_manager_unittest.cc
+++ b/media/gpu/ipc/service/picture_buffer_manager_unittest.cc
@@ -140,31 +140,6 @@
   environment_.RunUntilIdle();
 }
 
-TEST_F(PictureBufferManagerImplTest, ReusePictureBuffer_MultipleTime) {
-  constexpr size_t kFrameNum = 3;
-  Initialize();
-  PictureBuffer pb = CreateARGBPictureBuffer();
-  std::vector<scoped_refptr<VideoFrame>> frames;
-  for (size_t i = 0; i < kFrameNum; ++i) {
-    frames.push_back(CreateVideoFrame(pb.id()));
-  }
-
-  // Dropping the frame does not immediately trigger reuse.
-  std::vector<gpu::SyncToken> sync_tokens;
-  for (auto& frame : frames) {
-    sync_tokens.push_back(GenerateSyncToken(frame));
-  }
-  frames.clear();
-  environment_.RunUntilIdle();
-
-  // Completing the SyncToken wait does.
-  EXPECT_CALL(reuse_cb_, Run(pb.id())).Times(kFrameNum);
-  for (auto& sync_token : sync_tokens) {
-    cbh_->ReleaseSyncToken(sync_token);
-  }
-  environment_.RunUntilIdle();
-}
-
 TEST_F(PictureBufferManagerImplTest, DismissPictureBuffer_Available) {
   Initialize();
   PictureBuffer pb = CreateARGBPictureBuffer();
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index 28f19e30..0753fa0 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -181,7 +181,6 @@
 V4L2SliceVideoDecodeAccelerator::OutputRecord::OutputRecord()
     : at_device(false),
       at_client(false),
-      num_times_sent_to_client(0),
       picture_id(-1),
       texture_id(0),
       cleared(false) {}
@@ -402,8 +401,6 @@
  private:
   ~V4L2VP9Picture() override;
 
-  scoped_refptr<VP9Picture> CreateDuplicate() override;
-
   scoped_refptr<V4L2DecodeSurface> dec_surface_;
 
   DISALLOW_COPY_AND_ASSIGN(V4L2VP9Picture);
@@ -415,10 +412,6 @@
 
 V4L2VP9Picture::~V4L2VP9Picture() {}
 
-scoped_refptr<VP9Picture> V4L2VP9Picture::CreateDuplicate() {
-  return new V4L2VP9Picture(dec_surface_);
-}
-
 V4L2SliceVideoDecodeAccelerator::V4L2SliceVideoDecodeAccelerator(
     const scoped_refptr<V4L2Device>& device,
     EGLDisplay egl_display,
@@ -1294,10 +1287,6 @@
       output_buffer_queued_count_--;
     }
   }
-  // Mark as decoded to allow reuse.
-  for (auto kv : surfaces_at_device_) {
-    kv.second->SetDecoded();
-  }
   surfaces_at_device_.clear();
   DCHECK_EQ(output_buffer_queued_count_, 0);
 
@@ -1558,7 +1547,6 @@
     OutputRecord& output_record = output_buffer_map_[index];
     DCHECK(output_record.at_client);
     output_record.at_client = false;
-    output_record.num_times_sent_to_client = 0;
   }
   surfaces_at_display_.clear();
   DCHECK_EQ(free_output_buffers_.size(), output_buffer_map_.size());
@@ -1906,17 +1894,13 @@
     return;
   }
 
+  DCHECK(!output_record.egl_fence);
   DCHECK(!output_record.at_device);
-  --output_record.num_times_sent_to_client;
-  // A output buffer might be sent multiple times. We only use the last fence.
-  // When the last fence is signaled, all the previous fences must be executed.
-  if (output_record.num_times_sent_to_client == 0) {
-    output_record.at_client = false;
-    // Take ownership of the EGL fence.
-    output_record.egl_fence = std::move(egl_fence);
+  output_record.at_client = false;
+  // Take ownership of the EGL fence.
+  output_record.egl_fence = std::move(egl_fence);
 
-    surfaces_at_display_.erase(it);
-  }
+  surfaces_at_display_.erase(it);
 }
 
 void V4L2SliceVideoDecodeAccelerator::Flush() {
@@ -3201,26 +3185,16 @@
   OutputRecord& output_record =
       output_buffer_map_[dec_surface->output_record()];
 
-  if (output_record.num_times_sent_to_client == 0) {
-    DCHECK(!output_record.at_client);
-    output_record.at_client = true;
-    bool inserted =
-        surfaces_at_display_
-            .insert(std::make_pair(output_record.picture_id, dec_surface))
-            .second;
-    DCHECK(inserted);
-  } else {
-    // The surface is already sent to client, and not returned back yet.
-    DCHECK(output_record.at_client);
-    DCHECK(surfaces_at_display_.find(output_record.picture_id) !=
-           surfaces_at_display_.end());
-    CHECK(surfaces_at_display_[output_record.picture_id].get() ==
-          dec_surface.get());
-  }
+  bool inserted =
+      surfaces_at_display_
+          .insert(std::make_pair(output_record.picture_id, dec_surface))
+          .second;
+  DCHECK(inserted);
 
+  DCHECK(!output_record.at_client);
   DCHECK(!output_record.at_device);
   DCHECK_NE(output_record.picture_id, -1);
-  ++output_record.num_times_sent_to_client;
+  output_record.at_client = true;
 
   // TODO(hubbe): Insert correct color space. http://crbug.com/647725
   Picture picture(output_record.picture_id, bitstream_id,
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h
index d672268..467b525d 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.h
@@ -91,7 +91,6 @@
     ~OutputRecord();
     bool at_device;
     bool at_client;
-    size_t num_times_sent_to_client;
     int32_t picture_id;
     GLuint client_texture_id;
     GLuint texture_id;
diff --git a/media/gpu/vaapi/vaapi_common.cc b/media/gpu/vaapi/vaapi_common.cc
index af89a6a..909b736 100644
--- a/media/gpu/vaapi/vaapi_common.cc
+++ b/media/gpu/vaapi/vaapi_common.cc
@@ -33,8 +33,4 @@
   return this;
 }
 
-scoped_refptr<VP9Picture> VaapiVP9Picture::CreateDuplicate() {
-  return new VaapiVP9Picture(va_surface_);
-}
-
 }  // namespace media
diff --git a/media/gpu/vaapi/vaapi_common.h b/media/gpu/vaapi/vaapi_common.h
index 588961ff..6b9a074 100644
--- a/media/gpu/vaapi/vaapi_common.h
+++ b/media/gpu/vaapi/vaapi_common.h
@@ -64,8 +64,6 @@
   ~VaapiVP9Picture() override;
 
  private:
-  scoped_refptr<VP9Picture> CreateDuplicate() override;
-
   scoped_refptr<VASurface> va_surface_;
 
   DISALLOW_COPY_AND_ASSIGN(VaapiVP9Picture);
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc
index 569e38e5..354d467 100644
--- a/media/gpu/video_decode_accelerator_unittest.cc
+++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -370,12 +370,9 @@
   TextureRefMap active_textures_;
 
   // A map of the textures that are still pending in the renderer.
-  // The texture might be sent multiple times to the renderer in the case of VP9
-  // show_existing_frame feature, so we track it by multimap.
   // We check this to ensure all frames are rendered before entering the
   // CS_RESET_State.
-  std::multimap<int32_t, scoped_refptr<media::test::TextureRef>>
-      pending_textures_;
+  TextureRefMap pending_textures_;
 
   int32_t next_picture_buffer_id_;
 
@@ -584,16 +581,15 @@
       texture_target_, texture_it->second->texture_id(),
       base::Bind(&GLRenderingVDAClient::ReturnPicture, AsWeakPtr(),
                  picture.picture_buffer_id()));
-  pending_textures_.insert(*texture_it);
+  ASSERT_TRUE(pending_textures_.insert(*texture_it).second);
   rendering_helper_->ConsumeVideoFrame(config_.window_id,
                                        std::move(video_frame));
 }
 
 void GLRenderingVDAClient::ReturnPicture(int32_t picture_buffer_id) {
-  auto it = pending_textures_.find(picture_buffer_id);
-  LOG_ASSERT(it != pending_textures_.end());
-  pending_textures_.erase(it);
-
+  // Remove TextureRef from pending_textures_ regardless whether decoder is
+  // deleted.
+  LOG_ASSERT(1U == pending_textures_.erase(picture_buffer_id));
   if (decoder_deleted())
     return;
 
diff --git a/media/gpu/vp9_decoder.cc b/media/gpu/vp9_decoder.cc
index 72375b260..aefb38ba 100644
--- a/media/gpu/vp9_decoder.cc
+++ b/media/gpu/vp9_decoder.cc
@@ -108,16 +108,7 @@
         return kDecodeError;
       }
 
-      // Duplicate the VP9Picture and set the current bitstream id to keep the
-      // correct timestamp.
-      scoped_refptr<VP9Picture> pic = ref_frames_[frame_to_show]->Duplicate();
-      if (pic == nullptr) {
-        DVLOG(1) << "Failed to duplicate the VP9Picture.";
-        SetError();
-        return kDecodeError;
-      }
-      pic->set_bitstream_id(stream_id_);
-      if (!accelerator_->OutputPicture(std::move(pic))) {
+      if (!accelerator_->OutputPicture(ref_frames_[frame_to_show])) {
         SetError();
         return kDecodeError;
       }
diff --git a/media/gpu/vp9_picture.cc b/media/gpu/vp9_picture.cc
index e724886..07f9d8b 100644
--- a/media/gpu/vp9_picture.cc
+++ b/media/gpu/vp9_picture.cc
@@ -18,26 +18,4 @@
   return nullptr;
 }
 
-scoped_refptr<VP9Picture> VP9Picture::Duplicate() {
-  scoped_refptr<VP9Picture> ret = CreateDuplicate();
-  if (ret == nullptr)
-    return nullptr;
-
-  // Copy member of VP9Picture.
-  ret->frame_hdr.reset(new Vp9FrameHeader());
-  memcpy(ret->frame_hdr.get(), frame_hdr.get(), sizeof(Vp9FrameHeader));
-
-  // Copy member of CodecPicture.
-  // Note that decrypt_config_ is not used in here, so skip copying it.
-  ret->set_bitstream_id(bitstream_id());
-  ret->set_visible_rect(visible_rect());
-  ret->set_colorspace(get_colorspace());
-
-  return ret;
-}
-
-scoped_refptr<VP9Picture> VP9Picture::CreateDuplicate() {
-  return nullptr;
-}
-
 }  // namespace media
diff --git a/media/gpu/vp9_picture.h b/media/gpu/vp9_picture.h
index 312fe3d..84e63dc 100644
--- a/media/gpu/vp9_picture.h
+++ b/media/gpu/vp9_picture.h
@@ -24,20 +24,12 @@
   virtual V4L2VP9Picture* AsV4L2VP9Picture();
   virtual VaapiVP9Picture* AsVaapiVP9Picture();
 
-  // Create a duplicate instance and copy the data to it. It is used to support
-  // VP9 show_existing_frame feature. Return the scoped_refptr pointing to the
-  // duplicate instance, or nullptr on failure.
-  scoped_refptr<VP9Picture> Duplicate();
-
   std::unique_ptr<Vp9FrameHeader> frame_hdr;
 
  protected:
   ~VP9Picture() override;
 
  private:
-  // Create a duplicate instance.
-  virtual scoped_refptr<VP9Picture> CreateDuplicate();
-
   DISALLOW_COPY_AND_ASSIGN(VP9Picture);
 };
 
diff --git a/media/midi/usb_midi_descriptor_parser.cc b/media/midi/usb_midi_descriptor_parser.cc
index fad5e41e..b69cef69 100644
--- a/media/midi/usb_midi_descriptor_parser.cc
+++ b/media/midi/usb_midi_descriptor_parser.cc
@@ -256,10 +256,8 @@
 
   for (size_t i = 0; i < num_jacks; ++i) {
     uint8_t jack = data[kSizeForEmptyJacks + i];
-    std::vector<UsbMidiJack>::iterator it =
-        std::find_if(incomplete_jacks_.begin(),
-                     incomplete_jacks_.end(),
-                     JackMatcher(jack));
+    auto it = std::find_if(incomplete_jacks_.begin(), incomplete_jacks_.end(),
+                           JackMatcher(jack));
     if (it == incomplete_jacks_.end()) {
       DVLOG(1) << "A non-existing MIDI jack is associated.";
       return false;
diff --git a/media/test/data/README.md b/media/test/data/README.md
index f3d9625..8076f30 100644
--- a/media/test/data/README.md
+++ b/media/test/data/README.md
@@ -494,20 +494,6 @@
 MD5 of RGB thumbnail rendered version of test-25fps.vp9_2. Written out by
 video_decode_accelerator_unittest.
 
-### VP9 video with show_existing_frame flag
-
-#### vp90_2_10_show_existing_frame2.vp9.ivf
-VP9 video with show_existing_frame flag. The original test stream comes from
-Android CTS.
-```
-ffmpeg -i vp90_2_17_show_existing_frame.vp9 -vcodec copy -an -f ivf \
-    vp90_2_17_show_existing_frame.vp9.ivf
-```
-
-#### vp90_2_10_show_existing_frame2.vp9.ivf.md5
-MD5 of RGB thumbnail rendered version of vp90_2_10_show_existing_frame2.vp9.ivf.
-Written out by video_decode_accelerator_unittest.
-
 ### bear
 
 #### bear.h264
diff --git a/media/test/data/vp90_2_10_show_existing_frame2.vp9.ivf b/media/test/data/vp90_2_10_show_existing_frame2.vp9.ivf
deleted file mode 100644
index c60984c..0000000
--- a/media/test/data/vp90_2_10_show_existing_frame2.vp9.ivf
+++ /dev/null
Binary files differ
diff --git a/media/test/data/vp90_2_10_show_existing_frame2.vp9.ivf.md5 b/media/test/data/vp90_2_10_show_existing_frame2.vp9.ivf.md5
deleted file mode 100644
index 0d3acb7a..0000000
--- a/media/test/data/vp90_2_10_show_existing_frame2.vp9.ivf.md5
+++ /dev/null
@@ -1,5 +0,0 @@
-# --test_video_data="vp90_2_10_show_existing_frame2.vp9.ivf:352:288:16:16:35:150:12"
-# ARM - RK3399
-d810ba2a9a9326878b6a3b6a3f497dcd
-# Kabylake-Y
-50482ddcdeafa53d692d0d649ad48193
diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h
index 42ac1cb..c933f24 100644
--- a/media/video/video_decode_accelerator.h
+++ b/media/video/video_decode_accelerator.h
@@ -216,11 +216,6 @@
     virtual void DismissPictureBuffer(int32_t picture_buffer_id) = 0;
 
     // Callback to deliver decoded pictures ready to be displayed.
-    // Note: the decoded pictures might be sent to the client more than once.
-    // The client should call ReusePictureBuffer() once for each PictureReady().
-    // For example, VDA calls Client::PictureReady() twice for a picture buffer.
-    // Then the client should also call VDA::ReusePictureBuffer() twice.
-    // Until that, VDA cannot reuse the picture buffer.
     virtual void PictureReady(const Picture& picture) = 0;
 
     // Callback to notify that decoded has decoded the end of the current
@@ -314,11 +309,6 @@
   // Sends picture buffers to be reused by the decoder. This needs to be called
   // for each buffer that has been processed so that decoder may know onto which
   // picture buffers it can write the output to.
-  // Note: the decoded pictures might be sent to the client more than once.
-  // The client should call ReusePictureBuffer() once for each PictureReady().
-  // For example, VDA calls Client::PictureReady() twice for a picture buffer.
-  // Then the client should also call VDA::ReusePictureBuffer() twice.
-  // Until that, VDA can really reuse the picture buffer.
   //
   // Parameters:
   //  |picture_buffer_id| id of the picture buffer that is to be reused.
diff --git a/mojo/public/cpp/bindings/sync_call_restrictions.h b/mojo/public/cpp/bindings/sync_call_restrictions.h
index 0c5972ee..b260b9f0 100644
--- a/mojo/public/cpp/bindings/sync_call_restrictions.h
+++ b/mojo/public/cpp/bindings/sync_call_restrictions.h
@@ -21,10 +21,6 @@
 class PrefServiceSyncable;
 }
 
-namespace content {
-class BlinkTestController;
-}
-
 namespace leveldb {
 class LevelDBMojoProxy;
 }
@@ -96,8 +92,6 @@
   // For destroying the GL context/surface that draw to a platform window before
   // the platform window is destroyed.
   friend class viz::HostFrameSinkManager;
-  // Allow for layout test pixel dumps.
-  friend class content::BlinkTestController;
   // For preventing frame swaps of wrong size during resize on Windows.
   // (https://crbug.com/811945)
   friend class ui::HostContextFactoryPrivate;
diff --git a/net/base/network_change_notifier.cc b/net/base/network_change_notifier.cc
index b4f3d5f7..2361ffb 100644
--- a/net/base/network_change_notifier.cc
+++ b/net/base/network_change_notifier.cc
@@ -33,6 +33,8 @@
 #include "net/base/network_change_notifier_linux.h"
 #elif defined(OS_MACOSX)
 #include "net/base/network_change_notifier_mac.h"
+#elif defined(OS_FUCHSIA)
+#include "net/base/network_change_notifier_fuchsia.h"
 #endif
 
 namespace net {
@@ -217,6 +219,8 @@
   return new NetworkChangeNotifierLinux(std::unordered_set<std::string>());
 #elif defined(OS_MACOSX)
   return new NetworkChangeNotifierMac();
+#elif defined(OS_FUCHSIA)
+  return new NetworkChangeNotifierFuchsia();
 #else
   NOTIMPLEMENTED();
   return NULL;
diff --git a/net/base/network_change_notifier_linux.cc b/net/base/network_change_notifier_linux.cc
index 02901fd..9917306 100644
--- a/net/base/network_change_notifier_linux.cc
+++ b/net/base/network_change_notifier_linux.cc
@@ -63,6 +63,7 @@
 
 void NetworkChangeNotifierLinux::Thread::Init() {
   address_tracker_->Init();
+  last_type_ = GetCurrentConnectionType();
   dns_config_service_ = DnsConfigService::CreateSystemService();
   dns_config_service_->WatchConfig(
       base::Bind(&NetworkChangeNotifier::SetDnsConfig));
diff --git a/net/cert/x509_util.h b/net/cert/x509_util.h
index df28ec68..8d48701 100644
--- a/net/cert/x509_util.h
+++ b/net/cert/x509_util.h
@@ -34,9 +34,7 @@
 namespace x509_util {
 
 // Supported digest algorithms for signing certificates.
-enum DigestAlgorithm {
-  DIGEST_SHA256
-};
+enum DigestAlgorithm { DIGEST_SHA256 };
 
 // Generate a 'tls-server-end-point' channel binding based on the specified
 // certificate. Channel bindings are based on RFC 5929.
@@ -120,7 +118,7 @@
 
 // Creates a new X509Certificate from the chain in |buffers|, which must have at
 // least one element.
-scoped_refptr<X509Certificate> CreateX509CertificateFromBuffers(
+NET_EXPORT scoped_refptr<X509Certificate> CreateX509CertificateFromBuffers(
     const STACK_OF(CRYPTO_BUFFER) * buffers);
 
 // Returns the default ParseCertificateOptions for the net stack.
@@ -141,8 +139,8 @@
     base::span<const uint8_t> signature,
     const CRYPTO_BUFFER* certificate);
 
-} // namespace x509_util
+}  // namespace x509_util
 
-} // namespace net
+}  // namespace net
 
 #endif  // NET_CERT_X509_UTIL_H_
diff --git a/net/dns/BUILD.gn b/net/dns/BUILD.gn
index 0c2c199..0c03953 100644
--- a/net/dns/BUILD.gn
+++ b/net/dns/BUILD.gn
@@ -53,6 +53,8 @@
       "host_cache.cc",
       "host_resolver.cc",
       "host_resolver_impl.cc",
+      "host_resolver_mdns_task.cc",
+      "host_resolver_mdns_task.h",
       "host_resolver_proc.cc",
       "host_resolver_proc.h",
       "host_resolver_source.h",
@@ -459,8 +461,14 @@
   ]
 
   if (enable_mdns) {
-    sources += [ "mock_mdns_socket_factory.cc" ]
-    public += [ "mock_mdns_socket_factory.h" ]
+    sources += [
+      "mock_mdns_client.cc",
+      "mock_mdns_socket_factory.cc",
+    ]
+    public += [
+      "mock_mdns_client.h",
+      "mock_mdns_socket_factory.h",
+    ]
   }
 
   deps = [
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 3d29b9d2..cdad914 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -64,7 +64,9 @@
 #include "net/dns/dns_response.h"
 #include "net/dns/dns_transaction.h"
 #include "net/dns/dns_util.h"
+#include "net/dns/host_resolver_mdns_task.h"
 #include "net/dns/host_resolver_proc.h"
+#include "net/dns/mdns_client.h"
 #include "net/log/net_log.h"
 #include "net/log/net_log_capture_mode.h"
 #include "net/log/net_log_event_type.h"
@@ -76,6 +78,10 @@
 #include "net/socket/datagram_client_socket.h"
 #include "url/url_canon_ip.h"
 
+#if BUILDFLAG(ENABLE_MDNS)
+#include "net/dns/mdns_client_impl.h"
+#endif
+
 #if defined(OS_WIN)
 #include "net/base/winsock_init.h"
 #endif
@@ -1512,7 +1518,7 @@
       // This will destroy the Job.
       CompleteRequests(
           MakeCacheEntry(OK, addr_list, HostCache::Entry::SOURCE_HOSTS),
-          base::TimeDelta());
+          base::TimeDelta(), true /* allow_cache */);
       return true;
     }
     return false;
@@ -1525,7 +1531,7 @@
   }
 
   bool is_running() const {
-    return is_dns_running() || is_proc_running();
+    return is_dns_running() || is_mdns_running() || is_proc_running();
   }
 
  private:
@@ -1617,7 +1623,8 @@
     switch (key_.host_resolver_source) {
       case HostResolverSource::ANY:
         if (resolver_->HaveDnsConfig() &&
-            !ResemblesMulticastDNSName(key_.hostname)) {
+            !ResemblesMulticastDNSName(key_.hostname) &&
+            !(key_.host_resolver_flags & HOST_RESOLVER_CANONNAME)) {
           StartDnsTask();
         } else {
           StartProcTask();
@@ -1633,6 +1640,9 @@
 
         StartDnsTask();
         break;
+      case HostResolverSource::MULTICAST_DNS:
+        StartMdnsTask();
+        break;
     }
 
     // Caution: Job::Start must not complete synchronously.
@@ -1643,7 +1653,7 @@
   // TaskScheduler threads low, we will need to use an "inner"
   // PrioritizedDispatcher with tighter limits.
   void StartProcTask() {
-    DCHECK(!is_dns_running());
+    DCHECK(!is_running());
     proc_task_ = std::make_unique<ProcTask>(
         key_, resolver_->proc_params_,
         base::BindOnce(&Job::OnProcTaskComplete, base::Unretained(this),
@@ -1693,7 +1703,7 @@
     // Don't store the |ttl| in cache since it's not obtained from the server.
     CompleteRequests(
         MakeCacheEntry(net_error, addr_list, HostCache::Entry::SOURCE_UNKNOWN),
-        ttl);
+        ttl, true /* allow_cache */);
   }
 
   void StartDnsTask() {
@@ -1751,7 +1761,7 @@
       CompleteRequests(
           HostCache::Entry(net_error, AddressList(),
                            HostCache::Entry::Source::SOURCE_UNKNOWN, ttl),
-          ttl);
+          ttl, true /* allow_cache */);
     }
   }
 
@@ -1784,7 +1794,7 @@
     } else {
       CompleteRequests(MakeCacheEntryWithTTL(net_error, addr_list,
                                              HostCache::Entry::SOURCE_DNS, ttl),
-                       bounded_ttl);
+                       bounded_ttl, true /* allow_cache */);
     }
   }
 
@@ -1801,6 +1811,50 @@
       dns_task_->StartSecondTransaction();
   }
 
+  void StartMdnsTask() {
+    DCHECK(!is_running());
+
+    // No flags are supported for MDNS except
+    // HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6 (which is not actually an
+    // input flag).
+    DCHECK_EQ(0, key_.host_resolver_flags &
+                     ~HOST_RESOLVER_DEFAULT_FAMILY_SET_DUE_TO_NO_IPV6);
+
+    std::vector<HostResolver::DnsQueryType> query_types;
+    switch (key_.address_family) {
+      case ADDRESS_FAMILY_UNSPECIFIED:
+        query_types.push_back(HostResolver::DnsQueryType::A);
+        query_types.push_back(HostResolver::DnsQueryType::AAAA);
+        break;
+      case ADDRESS_FAMILY_IPV4:
+        query_types.push_back(HostResolver::DnsQueryType::A);
+        break;
+      case ADDRESS_FAMILY_IPV6:
+        query_types.push_back(HostResolver::DnsQueryType::AAAA);
+        break;
+    }
+
+    mdns_task_ = std::make_unique<HostResolverMdnsTask>(
+        resolver_->GetOrCreateMdnsClient(), key_.hostname, query_types);
+    mdns_task_->Start(
+        base::BindOnce(&Job::OnMdnsTaskComplete, base::Unretained(this)));
+  }
+
+  void OnMdnsTaskComplete(int error) {
+    DCHECK(is_mdns_running());
+    // TODO(crbug.com/846423): Consider adding MDNS-specific logging.
+
+    if (error != OK) {
+      CompleteRequestsWithError(error);
+    } else if (ContainsIcannNameCollisionIp(mdns_task_->result_addresses())) {
+      CompleteRequestsWithError(ERR_ICANN_NAME_COLLISION);
+    } else {
+      // MDNS uses a separate cache, so skip saving result to cache.
+      // TODO(crbug.com/846423): Consider merging caches.
+      CompleteRequestsWithoutCache(error, mdns_task_->result_addresses());
+    }
+  }
+
   URLRequestContext* url_request_context() override {
     return resolver_->url_request_context_;
   }
@@ -1880,8 +1934,12 @@
   }
 
   // Performs Job's last rites. Completes all Requests. Deletes this.
+  //
+  // If not |allow_cache|, result will not be stored in the host cache, even if
+  // result would otherwise allow doing so.
   void CompleteRequests(const HostCache::Entry& entry,
-                        base::TimeDelta ttl) {
+                        base::TimeDelta ttl,
+                        bool allow_cache) {
     CHECK(resolver_.get());
 
     // This job must be removed from resolver's |jobs_| now to make room for a
@@ -1893,6 +1951,7 @@
     if (is_running()) {
       proc_task_ = nullptr;
       KillDnsTask();
+      mdns_task_ = nullptr;
 
       // Signal dispatcher that a slot has opened.
       resolver_->dispatcher_->OnJobFinished();
@@ -1922,7 +1981,7 @@
 
     bool did_complete = (entry.error() != ERR_NETWORK_CHANGED) &&
                         (entry.error() != ERR_HOST_RESOLVER_QUEUE_TOO_LARGE);
-    if (did_complete)
+    if (did_complete && allow_cache)
       resolver_->CacheResult(key_, entry, ttl);
 
     RecordJobHistograms(entry.error());
@@ -1954,11 +2013,17 @@
     }
   }
 
+  void CompleteRequestsWithoutCache(int error, const AddressList& addresses) {
+    CompleteRequests(
+        MakeCacheEntry(error, addresses, HostCache::Entry::SOURCE_UNKNOWN),
+        base::TimeDelta(), false /* allow_cache */);
+  }
+
   // Convenience wrapper for CompleteRequests in case of failure.
   void CompleteRequestsWithError(int net_error) {
     CompleteRequests(HostCache::Entry(net_error, AddressList(),
                                       HostCache::Entry::SOURCE_UNKNOWN),
-                     base::TimeDelta());
+                     base::TimeDelta(), true /* allow_cache */);
   }
 
   RequestPriority priority() const override {
@@ -1972,6 +2037,8 @@
 
   bool is_dns_running() const { return !!dns_task_; }
 
+  bool is_mdns_running() const { return !!mdns_task_; }
+
   bool is_proc_running() const { return !!proc_task_; }
 
   base::WeakPtr<HostResolverImpl> resolver_;
@@ -2005,6 +2072,9 @@
   // Resolves the host using a DnsTransaction.
   std::unique_ptr<DnsTask> dns_task_;
 
+  // Resolves the host using MDnsClient.
+  std::unique_ptr<HostResolverMdnsTask> mdns_task_;
+
   // All Requests waiting for the result of this Job. Some can be canceled.
   base::LinkedList<RequestImpl> requests_;
 
@@ -2311,6 +2381,17 @@
   }
 }
 
+void HostResolverImpl::SetMdnsSocketFactoryForTesting(
+    std::unique_ptr<MDnsSocketFactory> socket_factory) {
+  DCHECK(!mdns_client_);
+  mdns_socket_factory_ = std::move(socket_factory);
+}
+
+void HostResolverImpl::SetMdnsClientForTesting(
+    std::unique_ptr<MDnsClient> client) {
+  mdns_client_ = std::move(client);
+}
+
 void HostResolverImpl::SetTaskRunnerForTesting(
     scoped_refptr<base::TaskRunner> task_runner) {
   proc_task_runner_ = std::move(task_runner);
@@ -2321,6 +2402,11 @@
   DCHECK(!request->job());
   // Request may only be resolved once.
   DCHECK(!request->complete());
+  // MDNS requests do not support skipping cache.
+  // TODO(crbug.com/846423): Either add support for skipping the MDNS cache, or
+  // merge to use the normal host cache for MDNS requests.
+  DCHECK(request->parameters().source != HostResolverSource::MULTICAST_DNS ||
+         request->parameters().allow_cached_response);
 
   request->set_request_time(tick_clock_->NowTicks());
 
@@ -2866,6 +2952,25 @@
                            std::abs(net_error));
 }
 
+MDnsClient* HostResolverImpl::GetOrCreateMdnsClient() {
+#if BUILDFLAG(ENABLE_MDNS)
+  if (!mdns_client_) {
+    if (!mdns_socket_factory_)
+      mdns_socket_factory_ = std::make_unique<MDnsSocketFactoryImpl>(net_log_);
+
+    mdns_client_ = MDnsClient::CreateDefault();
+    mdns_client_->StartListening(mdns_socket_factory_.get());
+  }
+
+  DCHECK(mdns_client_->IsListening());
+  return mdns_client_.get();
+#else
+  // Should not request MDNS resoltuion unless MDNS is enabled.
+  NOTREACHED();
+  return nullptr;
+#endif
+}
+
 HostResolverImpl::RequestImpl::~RequestImpl() {
   if (job_)
     job_->CancelRequest(this);
diff --git a/net/dns/host_resolver_impl.h b/net/dns/host_resolver_impl.h
index 5027c35..7336126b 100644
--- a/net/dns/host_resolver_impl.h
+++ b/net/dns/host_resolver_impl.h
@@ -35,6 +35,8 @@
 class AddressList;
 class DnsClient;
 class IPAddress;
+class MDnsClient;
+class MDnsSocketFactory;
 class NetLog;
 class NetLogWithSource;
 
@@ -187,6 +189,10 @@
   // Only allowed when the queue is empty.
   void SetMaxQueuedJobsForTesting(size_t value);
 
+  void SetMdnsSocketFactoryForTesting(
+      std::unique_ptr<MDnsSocketFactory> socket_factory);
+  void SetMdnsClientForTesting(std::unique_ptr<MDnsClient> client);
+
  protected:
   // Callback from HaveOnlyLoopbackAddresses probe.
   void SetHaveOnlyLoopbackAddresses(bool result);
@@ -345,6 +351,8 @@
   // and resulted in |net_error|.
   void OnDnsTaskResolve(int net_error);
 
+  MDnsClient* GetOrCreateMdnsClient();
+
   // Allows the tests to catch slots leaking out of the dispatcher.  One
   // HostResolverImpl::Job could occupy multiple PrioritizedDispatcher job
   // slots.
@@ -355,6 +363,11 @@
   // Cache of host resolution results.
   std::unique_ptr<HostCache> cache_;
 
+  // Used for multicast DNS tasks. Created on first use using
+  // GetOrCreateMndsClient().
+  std::unique_ptr<MDnsSocketFactory> mdns_socket_factory_;
+  std::unique_ptr<MDnsClient> mdns_client_;
+
   // Map from HostCache::Key to a Job.
   JobMap jobs_;
 
diff --git a/net/dns/host_resolver_impl_unittest.cc b/net/dns/host_resolver_impl_unittest.cc
index fdb1a0a..3920fdf 100644
--- a/net/dns/host_resolver_impl_unittest.cc
+++ b/net/dns/host_resolver_impl_unittest.cc
@@ -36,6 +36,8 @@
 #include "net/dns/dns_client.h"
 #include "net/dns/dns_test_util.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/dns/mock_mdns_client.h"
+#include "net/dns/mock_mdns_socket_factory.h"
 #include "net/log/net_log_event_type.h"
 #include "net/log/net_log_source_type.h"
 #include "net/log/net_log_with_source.h"
@@ -47,7 +49,11 @@
 
 using net::test::IsError;
 using net::test::IsOk;
+using ::testing::_;
+using ::testing::Between;
+using ::testing::ByMove;
 using ::testing::NotNull;
+using ::testing::Return;
 
 namespace net {
 
@@ -3012,6 +3018,274 @@
   EXPECT_EQ(1u, proc_->GetCaptureList().size());  // No increase.
 }
 
+#if BUILDFLAG(ENABLE_MDNS)
+const uint8_t kMdnsResponseA[] = {
+    // Header
+    0x00, 0x00,  // ID is zeroed out
+    0x81, 0x80,  // Standard query response, RA, no error
+    0x00, 0x00,  // No questions (for simplicity)
+    0x00, 0x01,  // 1 RR (answers)
+    0x00, 0x00,  // 0 authority RRs
+    0x00, 0x00,  // 0 additional RRs
+
+    // "myhello.local."
+    0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o', 0x05, 'l', 'o', 'c', 'a', 'l',
+    0x00,
+
+    0x00, 0x01,              // TYPE is A.
+    0x00, 0x01,              // CLASS is IN.
+    0x00, 0x00, 0x00, 0x10,  // TTL is 16 (seconds)
+    0x00, 0x04,              // RDLENGTH is 4 bytes.
+    0x01, 0x02, 0x03, 0x04,  // 1.2.3.4
+};
+
+const uint8_t kMdnsResponseAAAA[] = {
+    // Header
+    0x00, 0x00,  // ID is zeroed out
+    0x81, 0x80,  // Standard query response, RA, no error
+    0x00, 0x00,  // No questions (for simplicity)
+    0x00, 0x01,  // 1 RR (answers)
+    0x00, 0x00,  // 0 authority RRs
+    0x00, 0x00,  // 0 additional RRs
+
+    // "myhello.local."
+    0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o', 0x05, 'l', 'o', 'c', 'a', 'l',
+    0x00,
+
+    0x00, 0x1C,              // TYPE is AAAA.
+    0x00, 0x01,              // CLASS is IN.
+    0x00, 0x00, 0x00, 0x10,  // TTL is 16 (seconds)
+    0x00, 0x10,              // RDLENGTH is 16 bytes.
+
+    // 000a:0000:0000:0000:0001:0002:0003:0004
+    0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02,
+    0x00, 0x03, 0x00, 0x04,
+};
+
+// An MDNS response indicating that the responder owns the hostname, but the
+// specific requested type (AAAA) does not exist because the responder only has
+// A addresses.
+const uint8_t kMdnsResponseNsec[] = {
+    // Header
+    0x00, 0x00,  // ID is zeroed out
+    0x81, 0x80,  // Standard query response, RA, no error
+    0x00, 0x00,  // No questions (for simplicity)
+    0x00, 0x01,  // 1 RR (answers)
+    0x00, 0x00,  // 0 authority RRs
+    0x00, 0x00,  // 0 additional RRs
+
+    // "myhello.local."
+    0x07, 'm', 'y', 'h', 'e', 'l', 'l', 'o', 0x05, 'l', 'o', 'c', 'a', 'l',
+    0x00,
+
+    0x00, 0x2f,              // TYPE is NSEC.
+    0x00, 0x01,              // CLASS is IN.
+    0x00, 0x00, 0x00, 0x10,  // TTL is 16 (seconds)
+    0x00, 0x06,              // RDLENGTH is 6 bytes.
+    0xc0, 0x0c,  // Next Domain Name (always pointer back to name in MDNS)
+    0x00,        // Bitmap block number (always 0 in MDNS)
+    0x02,        // Bitmap length is 2
+    0x00, 0x08   // A type only
+};
+
+TEST_F(HostResolverImplTest, Mdns) {
+  auto socket_factory = std::make_unique<MockMDnsSocketFactory>();
+  MockMDnsSocketFactory* socket_factory_ptr = socket_factory.get();
+  resolver_->SetMdnsSocketFactoryForTesting(std::move(socket_factory));
+  // 2 socket creations for every transaction.
+  EXPECT_CALL(*socket_factory_ptr, OnSendTo(_)).Times(4);
+
+  HostResolver::ResolveHostParameters parameters;
+  parameters.source = HostResolverSource::MULTICAST_DNS;
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("myhello.local", 80), NetLogWithSource(), parameters));
+
+  socket_factory_ptr->SimulateReceive(kMdnsResponseA, sizeof(kMdnsResponseA));
+  socket_factory_ptr->SimulateReceive(kMdnsResponseAAAA,
+                                      sizeof(kMdnsResponseAAAA));
+
+  EXPECT_THAT(response.result_error(), IsOk());
+  EXPECT_THAT(
+      response.request()->GetAddressResults().value().endpoints(),
+      testing::UnorderedElementsAre(
+          CreateExpected("1.2.3.4", 80),
+          CreateExpected("000a:0000:0000:0000:0001:0002:0003:0004", 80)));
+}
+
+TEST_F(HostResolverImplTest, Mdns_AaaaOnly) {
+  auto socket_factory = std::make_unique<MockMDnsSocketFactory>();
+  MockMDnsSocketFactory* socket_factory_ptr = socket_factory.get();
+  resolver_->SetMdnsSocketFactoryForTesting(std::move(socket_factory));
+  // 2 socket creations for every transaction.
+  EXPECT_CALL(*socket_factory_ptr, OnSendTo(_)).Times(2);
+
+  HostResolver::ResolveHostParameters parameters;
+  parameters.dns_query_type = HostResolver::DnsQueryType::AAAA;
+  parameters.source = HostResolverSource::MULTICAST_DNS;
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("myhello.local", 80), NetLogWithSource(), parameters));
+
+  socket_factory_ptr->SimulateReceive(kMdnsResponseAAAA,
+                                      sizeof(kMdnsResponseAAAA));
+
+  EXPECT_THAT(response.result_error(), IsOk());
+  EXPECT_THAT(response.request()->GetAddressResults().value().endpoints(),
+              testing::ElementsAre(CreateExpected(
+                  "000a:0000:0000:0000:0001:0002:0003:0004", 80)));
+}
+
+// Test multicast DNS handling of NSEC responses (used for explicit negative
+// response).
+TEST_F(HostResolverImplTest, Mdns_Nsec) {
+  auto socket_factory = std::make_unique<MockMDnsSocketFactory>();
+  MockMDnsSocketFactory* socket_factory_ptr = socket_factory.get();
+  resolver_->SetMdnsSocketFactoryForTesting(std::move(socket_factory));
+  // 2 socket creations for every transaction.
+  EXPECT_CALL(*socket_factory_ptr, OnSendTo(_)).Times(2);
+
+  HostResolver::ResolveHostParameters parameters;
+  parameters.dns_query_type = HostResolver::DnsQueryType::AAAA;
+  parameters.source = HostResolverSource::MULTICAST_DNS;
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("myhello.local", 80), NetLogWithSource(), parameters));
+
+  socket_factory_ptr->SimulateReceive(kMdnsResponseNsec,
+                                      sizeof(kMdnsResponseNsec));
+
+  EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED));
+  EXPECT_FALSE(response.request()->GetAddressResults());
+}
+
+TEST_F(HostResolverImplTest, Mdns_NoResponse) {
+  auto socket_factory = std::make_unique<MockMDnsSocketFactory>();
+  MockMDnsSocketFactory* socket_factory_ptr = socket_factory.get();
+  resolver_->SetMdnsSocketFactoryForTesting(std::move(socket_factory));
+  // 2 socket creations for every transaction.
+  EXPECT_CALL(*socket_factory_ptr, OnSendTo(_)).Times(4);
+
+  // Add a little bit of extra fudge to the delay to allow reasonable
+  // flexibility for time > vs >= etc.  We don't need to fail the test if we
+  // timeout at t=6001 instead of t=6000.
+  base::TimeDelta kSleepFudgeFactor = base::TimeDelta::FromMilliseconds(1);
+
+  // Override the current thread task runner, so we can simulate the passage of
+  // time to trigger the timeout.
+  auto test_task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+  base::ScopedClosureRunner task_runner_override_scoped_cleanup =
+      base::ThreadTaskRunnerHandle::OverrideForTesting(test_task_runner);
+
+  HostResolver::ResolveHostParameters parameters;
+  parameters.source = HostResolverSource::MULTICAST_DNS;
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("myhello.local", 80), NetLogWithSource(), parameters));
+
+  ASSERT_TRUE(test_task_runner->HasPendingTask());
+  test_task_runner->FastForwardBy(MDnsTransaction::kTransactionTimeout +
+                                  kSleepFudgeFactor);
+
+  EXPECT_THAT(response.result_error(), IsError(ERR_NAME_NOT_RESOLVED));
+  EXPECT_FALSE(response.request()->GetAddressResults());
+
+  test_task_runner->FastForwardUntilNoTasksRemain();
+}
+
+// Test for a request for both A and AAAA results where results only exist for
+// one type.
+TEST_F(HostResolverImplTest, Mdns_PartialResults) {
+  auto socket_factory = std::make_unique<MockMDnsSocketFactory>();
+  MockMDnsSocketFactory* socket_factory_ptr = socket_factory.get();
+  resolver_->SetMdnsSocketFactoryForTesting(std::move(socket_factory));
+  // 2 socket creations for every transaction.
+  EXPECT_CALL(*socket_factory_ptr, OnSendTo(_)).Times(4);
+
+  // Add a little bit of extra fudge to the delay to allow reasonable
+  // flexibility for time > vs >= etc.  We don't need to fail the test if we
+  // timeout at t=6001 instead of t=6000.
+  base::TimeDelta kSleepFudgeFactor = base::TimeDelta::FromMilliseconds(1);
+
+  // Override the current thread task runner, so we can simulate the passage of
+  // time to trigger the timeout.
+  auto test_task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+  base::ScopedClosureRunner task_runner_override_scoped_cleanup =
+      base::ThreadTaskRunnerHandle::OverrideForTesting(test_task_runner);
+
+  HostResolver::ResolveHostParameters parameters;
+  parameters.source = HostResolverSource::MULTICAST_DNS;
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("myhello.local", 80), NetLogWithSource(), parameters));
+
+  ASSERT_TRUE(test_task_runner->HasPendingTask());
+
+  socket_factory_ptr->SimulateReceive(kMdnsResponseA, sizeof(kMdnsResponseA));
+  test_task_runner->FastForwardBy(MDnsTransaction::kTransactionTimeout +
+                                  kSleepFudgeFactor);
+
+  EXPECT_THAT(response.result_error(), IsOk());
+  EXPECT_THAT(response.request()->GetAddressResults().value().endpoints(),
+              testing::ElementsAre(CreateExpected("1.2.3.4", 80)));
+
+  test_task_runner->FastForwardUntilNoTasksRemain();
+}
+
+TEST_F(HostResolverImplTest, Mdns_Cancel) {
+  auto socket_factory = std::make_unique<MockMDnsSocketFactory>();
+  MockMDnsSocketFactory* socket_factory_ptr = socket_factory.get();
+  resolver_->SetMdnsSocketFactoryForTesting(std::move(socket_factory));
+  // 2 socket creations for every transaction.
+  EXPECT_CALL(*socket_factory_ptr, OnSendTo(_)).Times(4);
+
+  HostResolver::ResolveHostParameters parameters;
+  parameters.source = HostResolverSource::MULTICAST_DNS;
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("myhello.local", 80), NetLogWithSource(), parameters));
+
+  response.CancelRequest();
+
+  socket_factory_ptr->SimulateReceive(kMdnsResponseA, sizeof(kMdnsResponseA));
+  socket_factory_ptr->SimulateReceive(kMdnsResponseAAAA,
+                                      sizeof(kMdnsResponseAAAA));
+
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(response.complete());
+}
+
+// Test for a two-transaction query where the first fails to start. The second
+// should be cancelled.
+TEST_F(HostResolverImplTest, Mdns_PartialFailure) {
+  // Setup a mock MDnsClient where the first transaction will always return
+  // |false| immediately on Start(). Second transaction may or may not be
+  // created, but if it is, Start() not expected to be called because the
+  // overall request should immediately fail.
+  auto transaction1 = std::make_unique<MockMDnsTransaction>();
+  EXPECT_CALL(*transaction1, Start()).WillOnce(Return(false));
+  auto transaction2 = std::make_unique<MockMDnsTransaction>();
+  EXPECT_CALL(*transaction2, Start()).Times(0);
+
+  auto client = std::make_unique<MockMDnsClient>();
+  EXPECT_CALL(*client, CreateTransaction(_, _, _, _))
+      .Times(Between(1, 2))  // Second transaction optionally created.
+      .WillOnce(Return(ByMove(std::move(transaction1))))
+      .WillOnce(Return(ByMove(std::move(transaction2))));
+  EXPECT_CALL(*client, IsListening()).WillRepeatedly(Return(true));
+  resolver_->SetMdnsClientForTesting(std::move(client));
+
+  HostResolver::ResolveHostParameters parameters;
+  parameters.source = HostResolverSource::MULTICAST_DNS;
+
+  ResolveHostResponseHelper response(resolver_->CreateRequest(
+      HostPortPair("myhello.local", 80), NetLogWithSource(), parameters));
+
+  EXPECT_THAT(response.result_error(), IsError(ERR_FAILED));
+  EXPECT_FALSE(response.request()->GetAddressResults());
+}
+#endif  // BUILDFLAG(ENABLE_MDNS)
+
 DnsConfig CreateValidDnsConfig() {
   IPAddress dns_ip(192, 168, 1, 0);
   DnsConfig config;
diff --git a/net/dns/host_resolver_mdns_task.cc b/net/dns/host_resolver_mdns_task.cc
new file mode 100644
index 0000000..a2f7ba1b
--- /dev/null
+++ b/net/dns/host_resolver_mdns_task.cc
@@ -0,0 +1,208 @@
+// 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 "net/dns/host_resolver_mdns_task.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/logging.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/dns/dns_protocol.h"
+#include "net/dns/record_parsed.h"
+#include "net/dns/record_rdata.h"
+
+namespace net {
+
+class HostResolverMdnsTask::Transaction {
+ public:
+  Transaction(HostResolver::DnsQueryType query_type, HostResolverMdnsTask* task)
+      : query_type_(query_type), result_(ERR_IO_PENDING), task_(task) {}
+
+  void Start() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(task_->sequence_checker_);
+
+    // Should not be completed or running yet.
+    DCHECK_EQ(ERR_IO_PENDING, result_);
+    DCHECK(!async_transaction_);
+
+    uint16_t rrtype;
+    switch (query_type_) {
+      case net::HostResolver::DnsQueryType::A:
+        rrtype = net::dns_protocol::kTypeA;
+        break;
+      case net::HostResolver::DnsQueryType::AAAA:
+        rrtype = net::dns_protocol::kTypeAAAA;
+        break;
+      default:
+        // Type not supported for MDNS.
+        NOTREACHED();
+        return;
+    }
+
+    // TODO(crbug.com/846423): Use |allow_cached_response| to set the
+    // QUERY_CACHE flag or not.
+    int flags = MDnsTransaction::SINGLE_RESULT | MDnsTransaction::QUERY_CACHE |
+                MDnsTransaction::QUERY_NETWORK;
+    // If |this| is destroyed, destruction of |internal_transaction_| should
+    // cancel and prevent invocation of OnComplete.
+    std::unique_ptr<MDnsTransaction> inner_transaction =
+        task_->mdns_client_->CreateTransaction(
+            rrtype, task_->hostname_, flags,
+            base::BindRepeating(&HostResolverMdnsTask::Transaction::OnComplete,
+                                base::Unretained(this)));
+
+    // Side effect warning: Start() may finish and invoke callbacks inline.
+    bool start_result = inner_transaction->Start();
+
+    if (!start_result)
+      task_->CompleteWithResult(ERR_FAILED, true /* post_needed */);
+    else if (result_ == ERR_IO_PENDING)
+      async_transaction_ = std::move(inner_transaction);
+  }
+
+  bool IsDone() const { return result_ != ERR_IO_PENDING; }
+  bool IsError() const {
+    return IsDone() && result_ != OK && result_ != ERR_NAME_NOT_RESOLVED;
+  }
+  int result() const { return result_; }
+
+  void Cancel() {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(task_->sequence_checker_);
+    DCHECK_EQ(ERR_IO_PENDING, result_);
+
+    result_ = ERR_FAILED;
+    async_transaction_ = nullptr;
+  }
+
+ private:
+  void OnComplete(MDnsTransaction::Result result, const RecordParsed* parsed) {
+    DCHECK_CALLED_ON_VALID_SEQUENCE(task_->sequence_checker_);
+    DCHECK_EQ(ERR_IO_PENDING, result_);
+
+    switch (result) {
+      case MDnsTransaction::RESULT_RECORD:
+        result_ = OK;
+        break;
+      case MDnsTransaction::RESULT_NO_RESULTS:
+      case MDnsTransaction::RESULT_NSEC:
+        result_ = ERR_NAME_NOT_RESOLVED;
+        break;
+      default:
+        // No other results should be possible with the request flags used.
+        NOTREACHED();
+    }
+
+    if (result_ == net::OK) {
+      switch (query_type_) {
+        case net::HostResolver::DnsQueryType::A:
+          task_->result_addresses_.push_back(
+              IPEndPoint(parsed->rdata<net::ARecordRdata>()->address(), 0));
+          break;
+        case net::HostResolver::DnsQueryType::AAAA:
+          task_->result_addresses_.push_back(
+              IPEndPoint(parsed->rdata<net::AAAARecordRdata>()->address(), 0));
+          break;
+        default:
+          NOTREACHED();
+      }
+    }
+
+    // If we don't have a saved async_transaction, it means OnComplete was
+    // invoked inline in MDnsTransaction::Start. Callbacks will need to be
+    // invoked via post.
+    task_->CheckCompletion(!async_transaction_);
+  }
+
+  const HostResolver::DnsQueryType query_type_;
+
+  // ERR_IO_PENDING until transaction completes (or is cancelled).
+  int result_;
+
+  // Not saved until MDnsTransaction::Start completes to differentiate inline
+  // completion.
+  std::unique_ptr<MDnsTransaction> async_transaction_;
+
+  // Back pointer. Expected to destroy |this| before destroying itself.
+  HostResolverMdnsTask* const task_;
+};
+
+HostResolverMdnsTask::HostResolverMdnsTask(
+    MDnsClient* mdns_client,
+    const std::string& hostname,
+    const std::vector<HostResolver::DnsQueryType>& query_types)
+    : mdns_client_(mdns_client), hostname_(hostname), weak_ptr_factory_(this) {
+  DCHECK(!query_types.empty());
+  for (HostResolver::DnsQueryType query_type : query_types) {
+    transactions_.emplace_back(query_type, this);
+  }
+}
+
+HostResolverMdnsTask::~HostResolverMdnsTask() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  transactions_.clear();
+}
+
+void HostResolverMdnsTask::Start(CompletionOnceCallback completion_callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!completion_callback_);
+
+  completion_callback_ = std::move(completion_callback);
+
+  for (auto& transaction : transactions_) {
+    // Only start transaction if it is not already marked done. A transaction
+    // could be marked done before starting if it is preemptively canceled by
+    // a previously started transaction finishing with an error.
+    if (!transaction.IsDone())
+      transaction.Start();
+  }
+}
+
+void HostResolverMdnsTask::CheckCompletion(bool post_needed) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Finish immediately if any transactions completed with an error.
+  auto found_error =
+      std::find_if(transactions_.begin(), transactions_.end(),
+                   [](const Transaction& t) { return t.IsError(); });
+  if (found_error != transactions_.end()) {
+    CompleteWithResult(found_error->result(), post_needed);
+    return;
+  }
+
+  if (std::all_of(transactions_.begin(), transactions_.end(),
+                  [](const Transaction& t) { return t.IsDone(); })) {
+    // Task is overall successful if any of the transactions found results.
+    int result = result_addresses_.empty() ? ERR_NAME_NOT_RESOLVED : OK;
+
+    CompleteWithResult(result, post_needed);
+    return;
+  }
+}
+
+void HostResolverMdnsTask::CompleteWithResult(int result, bool post_needed) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Cancel any incomplete async transactions.
+  for (auto& transaction : transactions_) {
+    if (!transaction.IsDone())
+      transaction.Cancel();
+  }
+
+  if (post_needed) {
+    base::SequencedTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            [](base::WeakPtr<HostResolverMdnsTask> task, int result) {
+              if (task)
+                std::move(task->completion_callback_).Run(result);
+            },
+            weak_ptr_factory_.GetWeakPtr(), result));
+  } else {
+    std::move(completion_callback_).Run(result);
+  }
+}
+
+}  // namespace net
diff --git a/net/dns/host_resolver_mdns_task.h b/net/dns/host_resolver_mdns_task.h
new file mode 100644
index 0000000..eebf5ffc
--- /dev/null
+++ b/net/dns/host_resolver_mdns_task.h
@@ -0,0 +1,66 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_DNS_HOST_RESOLVER_MDNS_TASK_H_
+#define NET_DNS_HOST_RESOLVER_MDNS_TASK_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/containers/unique_ptr_adapters.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "net/base/completion_once_callback.h"
+#include "net/dns/host_resolver.h"
+#include "net/dns/mdns_client.h"
+
+namespace net {
+
+// Representation of a single HostResolverImpl::Job task to resolve the hostname
+// using multicast DNS transactions.  Destruction cancels the task and prevents
+// any callbacks from being invoked.
+class HostResolverMdnsTask {
+ public:
+  // |mdns_client| must outlive |this|.
+  HostResolverMdnsTask(
+      MDnsClient* mdns_client,
+      const std::string& hostname,
+      const std::vector<HostResolver::DnsQueryType>& query_types);
+  ~HostResolverMdnsTask();
+
+  // Starts the task. |completion_callback| will be called asynchronously with
+  // results.
+  //
+  // Should only be called once.
+  void Start(CompletionOnceCallback completion_callback);
+
+  const AddressList& result_addresses() { return result_addresses_; }
+
+ private:
+  class Transaction;
+
+  void CheckCompletion(bool post_needed);
+  void CompleteWithResult(int result, bool post_needed);
+
+  MDnsClient* const mdns_client_;
+
+  const std::string hostname_;
+
+  AddressList result_addresses_;
+  std::vector<Transaction> transactions_;
+
+  CompletionOnceCallback completion_callback_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  base::WeakPtrFactory<HostResolverMdnsTask> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(HostResolverMdnsTask);
+};
+
+}  // namespace net
+
+#endif  // NET_DNS_HOST_RESOLVER_MDNS_TASK_H_
diff --git a/net/dns/host_resolver_source.h b/net/dns/host_resolver_source.h
index 96af9b2..d873c07 100644
--- a/net/dns/host_resolver_source.h
+++ b/net/dns/host_resolver_source.h
@@ -21,7 +21,8 @@
   // Results will only come from DNS queries.
   DNS,
 
-  // TODO(crbug.com/846423): Add MDNS support.
+  // Results will only come from Multicast DNS queries.
+  MULTICAST_DNS,
 };
 
 }  // namespace net
diff --git a/net/dns/mdns_client.cc b/net/dns/mdns_client.cc
index 864acfd..f690140 100644
--- a/net/dns/mdns_client.cc
+++ b/net/dns/mdns_client.cc
@@ -45,6 +45,9 @@
 
 }  // namespace
 
+const base::TimeDelta MDnsTransaction::kTransactionTimeout =
+    base::TimeDelta::FromSeconds(3);
+
 // static
 std::unique_ptr<MDnsSocketFactory> MDnsSocketFactory::CreateDefault() {
   return std::unique_ptr<MDnsSocketFactory>(new MDnsSocketFactoryImpl);
diff --git a/net/dns/mdns_client.h b/net/dns/mdns_client.h
index 6348b1a..8a6213f 100644
--- a/net/dns/mdns_client.h
+++ b/net/dns/mdns_client.h
@@ -12,6 +12,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/time/time.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_export.h"
 #include "net/dns/dns_query.h"
@@ -32,6 +33,8 @@
 // time out after a reasonable number of seconds.
 class NET_EXPORT MDnsTransaction {
  public:
+  static const base::TimeDelta kTransactionTimeout;
+
   // Used to signify what type of result the transaction has received.
   enum Result {
     // Passed whenever a record is found.
diff --git a/net/dns/mdns_client_impl.cc b/net/dns/mdns_client_impl.cc
index d505c1a..40b319a 100644
--- a/net/dns/mdns_client_impl.cc
+++ b/net/dns/mdns_client_impl.cc
@@ -31,7 +31,6 @@
 
 namespace {
 
-const unsigned MDnsTransactionTimeoutSeconds = 3;
 // The fractions of the record's original TTL after which an active listener
 // (one that had |SetActiveRefresh(true)| called) will send a query to refresh
 // its cache. This happens both at 85% of the original TTL and again at 95% of
@@ -48,7 +47,7 @@
     DCHECK(interfaces[i].second == ADDRESS_FAMILY_IPV4 ||
            interfaces[i].second == ADDRESS_FAMILY_IPV6);
     std::unique_ptr<DatagramServerSocket> socket(CreateAndBindMDnsSocket(
-        interfaces[i].second, interfaces[i].first, nullptr));
+        interfaces[i].second, interfaces[i].first, net_log_));
     if (socket)
       sockets->push_back(std::move(socket));
   }
@@ -723,8 +722,7 @@
   timeout_.Reset(base::Bind(&MDnsTransactionImpl::SignalTransactionOver,
                             AsWeakPtr()));
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, timeout_.callback(),
-      base::TimeDelta::FromSeconds(MDnsTransactionTimeoutSeconds));
+      FROM_HERE, timeout_.callback(), kTransactionTimeout);
 
   return true;
 }
diff --git a/net/dns/mdns_client_impl.h b/net/dns/mdns_client_impl.h
index d9cd72834..7230855 100644
--- a/net/dns/mdns_client_impl.h
+++ b/net/dns/mdns_client_impl.h
@@ -34,15 +34,20 @@
 
 namespace net {
 
+class NetLog;
+
 class MDnsSocketFactoryImpl : public MDnsSocketFactory {
  public:
-  MDnsSocketFactoryImpl() {}
+  MDnsSocketFactoryImpl() : net_log_(nullptr) {}
+  explicit MDnsSocketFactoryImpl(NetLog* net_log) : net_log_(net_log) {}
   ~MDnsSocketFactoryImpl() override {}
 
   void CreateSockets(
       std::vector<std::unique_ptr<DatagramServerSocket>>* sockets) override;
 
  private:
+  NetLog* const net_log_;
+
   DISALLOW_COPY_AND_ASSIGN(MDnsSocketFactoryImpl);
 };
 
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc
index 299e776..43f4c5b2 100644
--- a/net/dns/mock_host_resolver.cc
+++ b/net/dns/mock_host_resolver.cc
@@ -331,6 +331,8 @@
   rules_map_[HostResolverSource::ANY] = CreateCatchAllHostResolverProc();
   rules_map_[HostResolverSource::SYSTEM] = CreateCatchAllHostResolverProc();
   rules_map_[HostResolverSource::DNS] = CreateCatchAllHostResolverProc();
+  rules_map_[HostResolverSource::MULTICAST_DNS] =
+      CreateCatchAllHostResolverProc();
 
   if (use_caching) {
     cache_.reset(new HostCache(kMaxCacheEntries));
diff --git a/net/dns/mock_mdns_client.cc b/net/dns/mock_mdns_client.cc
new file mode 100644
index 0000000..bbce796
--- /dev/null
+++ b/net/dns/mock_mdns_client.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 "net/dns/mock_mdns_client.h"
+
+namespace net {
+
+MockMDnsTransaction::MockMDnsTransaction() = default;
+
+MockMDnsTransaction::~MockMDnsTransaction() = default;
+
+MockMDnsClient::MockMDnsClient() = default;
+
+MockMDnsClient::~MockMDnsClient() = default;
+
+}  // namespace net
diff --git a/net/dns/mock_mdns_client.h b/net/dns/mock_mdns_client.h
new file mode 100644
index 0000000..0670caa
--- /dev/null
+++ b/net/dns/mock_mdns_client.h
@@ -0,0 +1,48 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_DNS_MOCK_MDNS_CLIENT_H_
+#define NET_DNS_MOCK_MDNS_CLIENT_H_
+
+#include <memory>
+#include <string>
+
+#include "net/dns/mdns_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace net {
+
+class MockMDnsTransaction : public MDnsTransaction {
+ public:
+  MockMDnsTransaction();
+  ~MockMDnsTransaction();
+
+  MOCK_METHOD0(Start, bool());
+  MOCK_CONST_METHOD0(GetName, const std::string&());
+  MOCK_CONST_METHOD0(GetType, uint16_t());
+};
+
+class MockMDnsClient : public MDnsClient {
+ public:
+  MockMDnsClient();
+  ~MockMDnsClient();
+
+  MOCK_METHOD3(CreateListener,
+               std::unique_ptr<MDnsListener>(uint16_t,
+                                             const std::string&,
+                                             MDnsListener::Delegate*));
+  MOCK_METHOD4(
+      CreateTransaction,
+      std::unique_ptr<MDnsTransaction>(uint16_t,
+                                       const std::string&,
+                                       int,
+                                       const MDnsTransaction::ResultCallback&));
+  MOCK_METHOD1(StartListening, bool(MDnsSocketFactory*));
+  MOCK_METHOD0(StopListening, void());
+  MOCK_CONST_METHOD0(IsListening, bool());
+};
+
+}  // namespace net
+
+#endif  // NET_DNS_MOCK_MDNS_CLIENT_H_
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 275a0903..57f847de 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -59610,8 +59610,21 @@
     { "name": "republicmo.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     { "name": "rincon-nsn.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     { "name": "safemt.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
-    { "name": "sequatchiecounty-tn.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     { "name": "usagm.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "claibornecountytn.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "delcopa.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "eastpeoria-il.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "evansville-wy.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "fbf.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "fortoglethorpega.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "gilescountytn.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "glencoveny.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "gonzalesca.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "kielwi.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "rva.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "sequatchiecountytn.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "votewa.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
+    { "name": "zerowastesonoma.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     { "name": "bmoattachments.org", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
     // END OF ETLD-OWNER REQUESTED ENTRIES
 
diff --git a/remoting/client/input/key_event_mapper.cc b/remoting/client/input/key_event_mapper.cc
index 79e84f92..4376a12 100644
--- a/remoting/client/input/key_event_mapper.cc
+++ b/remoting/client/input/key_event_mapper.cc
@@ -45,8 +45,7 @@
     }
 
     // Re-map mapped keys to the new value before passing them on.
-    std::map<uint32_t, uint32_t>::iterator mapped =
-        mapped_keys.find(event.usb_keycode());
+    auto mapped = mapped_keys.find(event.usb_keycode());
     if (mapped != mapped_keys.end()) {
       protocol::KeyEvent new_event(event);
       new_event.set_usb_keycode(mapped->second);
diff --git a/remoting/client/input/normalizing_input_filter_mac.cc b/remoting/client/input/normalizing_input_filter_mac.cc
index 0197953..82bd4d5 100644
--- a/remoting/client/input/normalizing_input_filter_mac.cc
+++ b/remoting/client/input/normalizing_input_filter_mac.cc
@@ -71,8 +71,7 @@
 }
 
 void NormalizingInputFilterMac::GenerateKeyupEvents() {
-  for (KeyPressedMap::iterator i = key_pressed_map_.begin();
-       i != key_pressed_map_.end(); ++i) {
+  for (auto i = key_pressed_map_.begin(); i != key_pressed_map_.end(); ++i) {
     // The generated key up event will have the same key code and lock states
     // as the original key down event.
     protocol::KeyEvent event = i->second;
diff --git a/remoting/host/chromoting_host.cc b/remoting/host/chromoting_host.cc
index 4fcc853c..a45e426 100644
--- a/remoting/host/chromoting_host.cc
+++ b/remoting/host/chromoting_host.cc
@@ -189,11 +189,10 @@
 void ChromotingHost::OnSessionClosed(ClientSession* client) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  ClientSessions::iterator it =
-      std::find_if(clients_.begin(), clients_.end(),
-                   [client](const std::unique_ptr<ClientSession>& item) {
-                     return item.get() == client;
-                   });
+  auto it = std::find_if(clients_.begin(), clients_.end(),
+                         [client](const std::unique_ptr<ClientSession>& item) {
+                           return item.get() == client;
+                         });
   CHECK(it != clients_.end());
 
   bool was_authenticated = client->is_authenticated();
diff --git a/remoting/host/ipc_desktop_environment.cc b/remoting/host/ipc_desktop_environment.cc
index f192e8ad..4a452b7 100644
--- a/remoting/host/ipc_desktop_environment.cc
+++ b/remoting/host/ipc_desktop_environment.cc
@@ -176,7 +176,7 @@
     return;
   }
 
-  ActiveConnectionsList::iterator i = active_connections_.find(terminal_id);
+  auto i = active_connections_.find(terminal_id);
   if (i != active_connections_.end()) {
     i->second->DetachFromDesktop();
     i->second->AttachToDesktop(desktop_pipe, session_id);
@@ -193,7 +193,7 @@
     return;
   }
 
-  ActiveConnectionsList::iterator i = active_connections_.find(terminal_id);
+  auto i = active_connections_.find(terminal_id);
   if (i != active_connections_.end()) {
     DesktopSessionProxy* desktop_session_proxy = i->second;
     active_connections_.erase(i);
diff --git a/remoting/host/remote_input_filter.cc b/remoting/host/remote_input_filter.cc
index b4f4ab1..8795bc74 100644
--- a/remoting/host/remote_input_filter.cc
+++ b/remoting/host/remote_input_filter.cc
@@ -38,8 +38,7 @@
   // input event that we've just injected), then ignore remote inputs for a
   // short time.
   if (expect_local_echo_) {
-    std::list<webrtc::DesktopVector>::iterator found_position =
-        injected_mouse_positions_.begin();
+    auto found_position = injected_mouse_positions_.begin();
     while (found_position != injected_mouse_positions_.end() &&
            !mouse_pos.equals(*found_position)) {
       ++found_position;
diff --git a/remoting/host/security_key/security_key_auth_handler_posix.cc b/remoting/host/security_key/security_key_auth_handler_posix.cc
index 371ba3f..ee1866a8 100644
--- a/remoting/host/security_key/security_key_auth_handler_posix.cc
+++ b/remoting/host/security_key/security_key_auth_handler_posix.cc
@@ -201,7 +201,7 @@
 void SecurityKeyAuthHandlerPosix::SendClientResponse(
     int connection_id,
     const std::string& response) {
-  ActiveSockets::const_iterator iter = GetSocketForConnectionId(connection_id);
+  auto iter = GetSocketForConnectionId(connection_id);
   if (iter != active_sockets_.end()) {
     HOST_DLOG << "Sending client response to socket: " << connection_id;
     iter->second->SendResponse(response);
@@ -214,7 +214,7 @@
 }
 
 void SecurityKeyAuthHandlerPosix::SendErrorAndCloseConnection(int id) {
-  ActiveSockets::const_iterator iter = GetSocketForConnectionId(id);
+  auto iter = GetSocketForConnectionId(id);
   if (iter != active_sockets_.end()) {
     HOST_DLOG << "Sending error and closing socket: " << id;
     SendErrorAndCloseActiveSocket(iter);
diff --git a/remoting/protocol/channel_multiplexer.cc b/remoting/protocol/channel_multiplexer.cc
index 6be161e..313b351 100644
--- a/remoting/protocol/channel_multiplexer.cc
+++ b/remoting/protocol/channel_multiplexer.cc
@@ -348,8 +348,8 @@
 }
 
 void ChannelMultiplexer::CancelChannelCreation(const std::string& name) {
-  for (std::list<PendingChannel>::iterator it = pending_channels_.begin();
-       it != pending_channels_.end(); ++it) {
+  for (auto it = pending_channels_.begin(); it != pending_channels_.end();
+       ++it) {
     if (it->name == name) {
       pending_channels_.erase(it);
       return;
@@ -442,8 +442,7 @@
 
   int receive_id = packet->channel_id();
   MuxChannel* channel = nullptr;
-  std::map<int, MuxChannel*>::iterator it =
-      channels_by_receive_id_.find(receive_id);
+  auto it = channels_by_receive_id_.find(receive_id);
   if (it != channels_by_receive_id_.end()) {
     channel = it->second;
   } else {
diff --git a/remoting/protocol/client_video_dispatcher.cc b/remoting/protocol/client_video_dispatcher.cc
index 2b0d5b50..b29b5a585 100644
--- a/remoting/protocol/client_video_dispatcher.cc
+++ b/remoting/protocol/client_video_dispatcher.cc
@@ -90,7 +90,7 @@
     client_stub_->SetVideoLayout(layout);
   }
 
-  PendingFramesList::iterator pending_frame =
+  auto pending_frame =
       pending_frames_.insert(pending_frames_.end(), PendingFrame(frame_id));
 
   video_stub_->ProcessVideoPacket(
diff --git a/remoting/protocol/fake_datagram_socket.cc b/remoting/protocol/fake_datagram_socket.cc
index 91eedb6..1b06864 100644
--- a/remoting/protocol/fake_datagram_socket.cc
+++ b/remoting/protocol/fake_datagram_socket.cc
@@ -135,8 +135,7 @@
 }
 
 FakeDatagramChannelFactory::~FakeDatagramChannelFactory() {
-  for (ChannelsMap::iterator it = channels_.begin(); it != channels_.end();
-       ++it) {
+  for (auto it = channels_.begin(); it != channels_.end(); ++it) {
     EXPECT_FALSE(it->second);
   }
 }
diff --git a/remoting/protocol/ice_transport.cc b/remoting/protocol/ice_transport.cc
index ff782f0d..9c04e52 100644
--- a/remoting/protocol/ice_transport.cc
+++ b/remoting/protocol/ice_transport.cc
@@ -60,7 +60,7 @@
 
   for (auto it = transport_info.ice_credentials.begin();
        it != transport_info.ice_credentials.end(); ++it) {
-    ChannelsMap::iterator channel = channels_.find(it->channel);
+    auto channel = channels_.find(it->channel);
     if (channel != channels_.end()) {
       channel->second->SetRemoteCredentials(it->ufrag, it->password);
     } else {
@@ -72,7 +72,7 @@
 
   for (auto it = transport_info.candidates.begin();
        it != transport_info.candidates.end(); ++it) {
-    ChannelsMap::iterator channel = channels_.find(it->name);
+    auto channel = channels_.find(it->name);
     rtc::SocketAddress address = ToNativeSocket(it->candidate.address());
     it->candidate.set_address(address);
     if (channel != channels_.end()) {
@@ -114,7 +114,7 @@
 }
 
 void IceTransport::CancelChannelCreation(const std::string& name) {
-  ChannelsMap::iterator it = channels_.find(name);
+  auto it = channels_.find(name);
   if (it != channels_.end()) {
     DCHECK(!it->second->is_connected());
     delete it->second;
@@ -123,8 +123,7 @@
 }
 
 void IceTransport::AddPendingRemoteTransportInfo(IceTransportChannel* channel) {
-  std::list<IceTransportInfo::IceCredentials>::iterator credentials =
-      pending_remote_ice_credentials_.begin();
+  auto credentials = pending_remote_ice_credentials_.begin();
   while (credentials != pending_remote_ice_credentials_.end()) {
     if (credentials->channel == channel->name()) {
       channel->SetRemoteCredentials(credentials->ufrag, credentials->password);
@@ -134,8 +133,7 @@
     }
   }
 
-  std::list<IceTransportInfo::NamedCandidate>::iterator candidate =
-      pending_remote_candidates_.begin();
+  auto candidate = pending_remote_candidates_.begin();
   while (candidate != pending_remote_candidates_.end()) {
     if (candidate->name == channel->name()) {
       channel->AddRemoteCandidate(candidate->candidate);
@@ -172,7 +170,7 @@
 }
 
 void IceTransport::OnChannelDeleted(IceTransportChannel* channel) {
-  ChannelsMap::iterator it = channels_.find(channel->name());
+  auto it = channels_.find(channel->name());
   DCHECK_EQ(it->second, channel);
   channels_.erase(it);
 }
diff --git a/remoting/protocol/jingle_session_manager.cc b/remoting/protocol/jingle_session_manager.cc
index b039ae7d..33cdab1 100644
--- a/remoting/protocol/jingle_session_manager.cc
+++ b/remoting/protocol/jingle_session_manager.cc
@@ -128,7 +128,7 @@
     return true;
   }
 
-  SessionsMap::iterator it = sessions_.find(message->sid);
+  auto it = sessions_.find(message->sid);
   if (it == sessions_.end()) {
     SendReply(std::move(stanza_copy), JingleMessageReply::INVALID_SID);
     return true;
diff --git a/remoting/protocol/pseudotcp_channel_factory.cc b/remoting/protocol/pseudotcp_channel_factory.cc
index 9adf225..9e466ba 100644
--- a/remoting/protocol/pseudotcp_channel_factory.cc
+++ b/remoting/protocol/pseudotcp_channel_factory.cc
@@ -49,7 +49,7 @@
 }
 
 void PseudoTcpChannelFactory::CancelChannelCreation(const std::string& name) {
-  PendingSocketsMap::iterator it = pending_sockets_.find(name);
+  auto it = pending_sockets_.find(name);
   if (it == pending_sockets_.end()) {
     datagram_channel_factory_->CancelChannelCreation(name);
   } else {
@@ -86,7 +86,7 @@
     const std::string& name,
     const ChannelCreatedCallback& callback,
     int result) {
-  PendingSocketsMap::iterator it = pending_sockets_.find(name);
+  auto it = pending_sockets_.find(name);
   DCHECK(it != pending_sockets_.end());
   std::unique_ptr<P2PStreamSocket> socket(it->second);
   pending_sockets_.erase(it);
diff --git a/remoting/protocol/secure_channel_factory.cc b/remoting/protocol/secure_channel_factory.cc
index 40b02a0..d87063e9b 100644
--- a/remoting/protocol/secure_channel_factory.cc
+++ b/remoting/protocol/secure_channel_factory.cc
@@ -39,7 +39,7 @@
 
 void SecureChannelFactory::CancelChannelCreation(
     const std::string& name) {
-  AuthenticatorMap::iterator it = channel_authenticators_.find(name);
+  auto it = channel_authenticators_.find(name);
   if (it == channel_authenticators_.end()) {
     channel_factory_->CancelChannelCreation(name);
   } else {
@@ -73,7 +73,7 @@
     std::unique_ptr<P2PStreamSocket> socket) {
   DCHECK((socket && error == net::OK) || (!socket && error != net::OK));
 
-  AuthenticatorMap::iterator it = channel_authenticators_.find(name);
+  auto it = channel_authenticators_.find(name);
   DCHECK(it != channel_authenticators_.end());
   delete it->second;
   channel_authenticators_.erase(it);
diff --git a/remoting/signaling/iq_sender.cc b/remoting/signaling/iq_sender.cc
index 1e6b494..a1c568d 100644
--- a/remoting/signaling/iq_sender.cc
+++ b/remoting/signaling/iq_sender.cc
@@ -72,9 +72,9 @@
 }
 
 void IqSender::RemoveRequest(IqRequest* request) {
-  IqRequestMap::iterator it = requests_.begin();
+  auto it = requests_.begin();
   while (it != requests_.end()) {
-    IqRequestMap::iterator cur = it;
+    auto cur = it;
     ++it;
     if (cur->second == request) {
       requests_.erase(cur);
@@ -110,7 +110,7 @@
 
   std::string from = stanza->Attr(buzz::QN_FROM);
 
-  IqRequestMap::iterator it = requests_.find(id);
+  auto it = requests_.find(id);
   if (it == requests_.end()) {
     return false;
   }
diff --git a/remoting/signaling/server_log_entry_unittest.cc b/remoting/signaling/server_log_entry_unittest.cc
index 80b5b22..00e2c96 100644
--- a/remoting/signaling/server_log_entry_unittest.cc
+++ b/remoting/signaling/server_log_entry_unittest.cc
@@ -68,8 +68,7 @@
     }
     const std::string& key = attr->Name().LocalPart();
     const std::string& value = attr->Value();
-    std::map<std::string, std::string>::const_iterator iter =
-        key_value_pairs.find(key);
+    auto iter = key_value_pairs.find(key);
     if (iter == key_value_pairs.end()) {
       if (keys.find(key) == keys.end()) {
         *error = "unexpected attribute " + key;
diff --git a/remoting/test/fake_network_dispatcher.cc b/remoting/test/fake_network_dispatcher.cc
index dad459f5..0c96e07 100644
--- a/remoting/test/fake_network_dispatcher.cc
+++ b/remoting/test/fake_network_dispatcher.cc
@@ -62,7 +62,7 @@
   {
     base::AutoLock auto_lock(nodes_lock_);
 
-    NodesMap::iterator node_it = nodes_.find(to.ipaddr());
+    auto node_it = nodes_.find(to.ipaddr());
     if (node_it == nodes_.end()) {
       LOG(ERROR) << "Tried to deliver packet to unknown target: "
                  << to.ToString();
diff --git a/remoting/test/fake_socket_factory.cc b/remoting/test/fake_socket_factory.cc
index 8851572d..cda9fff 100644
--- a/remoting/test/fake_socket_factory.cc
+++ b/remoting/test/fake_socket_factory.cc
@@ -336,7 +336,7 @@
 
   PendingPacket packet;
   if (pending_packets_.size() > 1 && RandDouble() < out_of_order_rate_) {
-    std::list<PendingPacket>::iterator it = pending_packets_.begin();
+    auto it = pending_packets_.begin();
     ++it;
     packet = *it;
     pending_packets_.erase(it);
@@ -345,7 +345,7 @@
     pending_packets_.pop_front();
   }
 
-  UdpSocketsMap::iterator iter = udp_sockets_.find(packet.to.port());
+  auto iter = udp_sockets_.find(packet.to.port());
   if (iter == udp_sockets_.end()) {
     // Invalid port number.
     return;
diff --git a/services/audio/audio_sandbox_win.cc b/services/audio/audio_sandbox_win.cc
index c47e0841..9285b49a 100644
--- a/services/audio/audio_sandbox_win.cc
+++ b/services/audio/audio_sandbox_win.cc
@@ -43,6 +43,13 @@
   policy->SetTokenLevel(sandbox::USER_RESTRICTED_SAME_ACCESS,
                         sandbox::USER_NON_ADMIN);
   policy->SetDelayedIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
+
+  // Custom default policy allowing audio drivers to read device properties
+  // (https://crbug.com/883326).
+  policy->SetIntegrityLevel(sandbox::INTEGRITY_LEVEL_LOW);
+  policy->SetLockdownDefaultDacl();
+  policy->SetAlternateDesktop(true);
+
   return true;
 }
 
diff --git a/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc b/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
index e9ff663..2554eb4 100644
--- a/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
+++ b/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/win/iunknown_impl.h"
 #include "base/win/propvarutil.h"
 #include "base/win/scoped_propvariant.h"
@@ -189,7 +190,12 @@
 //                         data in OnDataUpdated event.
 class PlatformSensorAndProviderTestWin : public ::testing::Test {
  public:
+  PlatformSensorAndProviderTestWin()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+
   void SetUp() override {
+    EXPECT_EQ(S_OK, CoInitialize(nullptr));
     sensor_ = new NiceMock<MockISensor>();
     sensor_collection_ = new NiceMock<MockISensorCollection>();
     sensor_manager_ = new NiceMock<MockISensorManager>();
@@ -244,7 +250,7 @@
 
   void SetUnsupportedSensor(REFSENSOR_TYPE_ID sensor) {
     EXPECT_CALL(*sensor_manager_, GetSensorsByType(sensor, _))
-        .WillOnce(Invoke(
+        .WillRepeatedly(Invoke(
             [this](REFSENSOR_TYPE_ID type, ISensorCollection** collection) {
               return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
             }));
@@ -288,7 +294,7 @@
           events->AddRef();
           sensor_events_.Attach(events);
           if (this->run_loop_) {
-            message_loop_.task_runner()->PostTask(
+            scoped_task_environment_.GetMainThreadTaskRunner()->PostTask(
                 FROM_HERE,
                 base::Bind(&PlatformSensorAndProviderTestWin::QuitInnerLoop,
                            base::Unretained(this)));
@@ -302,7 +308,7 @@
         .WillByDefault(Invoke([this](ISensorEvents* events) {
           sensor_events_.Reset();
           if (this->run_loop_) {
-            message_loop_.task_runner()->PostTask(
+            scoped_task_environment_.GetMainThreadTaskRunner()->PostTask(
                 FROM_HERE,
                 base::Bind(&PlatformSensorAndProviderTestWin::QuitInnerLoop,
                            base::Unretained(this)));
@@ -382,11 +388,11 @@
     sensor_events_->OnDataUpdated(sensor_.get(), data_report.Get());
   }
 
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   scoped_refptr<MockISensorManager> sensor_manager_;
   scoped_refptr<MockISensorCollection> sensor_collection_;
   scoped_refptr<MockISensor> sensor_;
   Microsoft::WRL::ComPtr<ISensorEvents> sensor_events_;
-  base::MessageLoop message_loop_;
   scoped_refptr<PlatformSensor> platform_sensor_;
   // Inner run loop used to wait for async sensor creation callback.
   std::unique_ptr<base::RunLoop> run_loop_;
diff --git a/services/device/generic_sensor/platform_sensor_provider_win.cc b/services/device/generic_sensor/platform_sensor_provider_win.cc
index 346ba7d..6aab338 100644
--- a/services/device/generic_sensor/platform_sensor_provider_win.cc
+++ b/services/device/generic_sensor/platform_sensor_provider_win.cc
@@ -10,6 +10,8 @@
 #include <iomanip>
 
 #include "base/memory/singleton.h"
+#include "base/task/post_task.h"
+#include "base/task/task_traits.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread.h"
 #include "services/device/generic_sensor/linear_acceleration_fusion_algorithm_using_accelerometer.h"
@@ -19,44 +21,6 @@
 
 namespace device {
 
-class PlatformSensorProviderWin::SensorThread final : public base::Thread {
- public:
-  SensorThread() : base::Thread("Sensor thread") { init_com_with_mta(true); }
-
-  void SetSensorManagerForTesting(
-      Microsoft::WRL::ComPtr<ISensorManager> sensor_manager) {
-    sensor_manager_ = sensor_manager;
-  }
-
-  const Microsoft::WRL::ComPtr<ISensorManager>& sensor_manager() const {
-    return sensor_manager_;
-  }
-
- protected:
-  void Init() override {
-    if (sensor_manager_)
-      return;
-    HRESULT hr = ::CoCreateInstance(CLSID_SensorManager, nullptr, CLSCTX_ALL,
-                                    IID_PPV_ARGS(&sensor_manager_));
-    if (FAILED(hr)) {
-      // Only log this error the first time.
-      static bool logged_failure = false;
-      if (!logged_failure) {
-        LOG(ERROR) << "Unable to create instance of SensorManager: "
-                   << _com_error(hr).ErrorMessage() << " (0x" << std::hex
-                   << std::uppercase << std::setfill('0') << std::setw(8) << hr
-                   << ")";
-        logged_failure = true;
-      }
-    }
-  }
-
-  void CleanUp() override { sensor_manager_.Reset(); }
-
- private:
-  Microsoft::WRL::ComPtr<ISensorManager> sensor_manager_;
-};
-
 // static
 PlatformSensorProviderWin* PlatformSensorProviderWin::GetInstance() {
   return base::Singleton<
@@ -66,11 +30,13 @@
 
 void PlatformSensorProviderWin::SetSensorManagerForTesting(
     Microsoft::WRL::ComPtr<ISensorManager> sensor_manager) {
-  CreateSensorThread();
-  sensor_thread_->SetSensorManagerForTesting(sensor_manager);
+  sensor_manager_ = sensor_manager;
 }
 
-PlatformSensorProviderWin::PlatformSensorProviderWin() = default;
+PlatformSensorProviderWin::PlatformSensorProviderWin()
+    : com_sta_task_runner_(base::CreateCOMSTATaskRunnerWithTraits(
+          base::TaskPriority::USER_VISIBLE)) {}
+
 PlatformSensorProviderWin::~PlatformSensorProviderWin() = default;
 
 void PlatformSensorProviderWin::CreateSensorInternal(
@@ -78,7 +44,43 @@
     SensorReadingSharedBuffer* reading_buffer,
     const CreateSensorCallback& callback) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  if (!StartSensorThread()) {
+  if (sensor_manager_) {
+    OnInitSensorManager(type, reading_buffer, callback);
+  } else {
+    com_sta_task_runner_->PostTaskAndReply(
+        FROM_HERE,
+        base::Bind(&PlatformSensorProviderWin::InitSensorManager,
+                   base::Unretained(this)),
+        base::Bind(&PlatformSensorProviderWin::OnInitSensorManager,
+                   base::Unretained(this), type, reading_buffer, callback));
+  }
+}
+
+void PlatformSensorProviderWin::InitSensorManager() {
+  DCHECK(com_sta_task_runner_->RunsTasksInCurrentSequence());
+
+  HRESULT hr = ::CoCreateInstance(CLSID_SensorManager, nullptr, CLSCTX_ALL,
+                                  IID_PPV_ARGS(&sensor_manager_));
+  if (FAILED(hr)) {
+    // Only log this error the first time.
+    static bool logged_failure = false;
+    if (!logged_failure) {
+      LOG(ERROR) << "Unable to create instance of SensorManager: "
+                 << _com_error(hr).ErrorMessage() << " (0x" << std::hex
+                 << std::uppercase << std::setfill('0') << std::setw(8) << hr
+                 << ")";
+      logged_failure = true;
+    }
+  }
+}
+
+void PlatformSensorProviderWin::OnInitSensorManager(
+    mojom::SensorType type,
+    SensorReadingSharedBuffer* reading_buffer,
+    const CreateSensorCallback& callback) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+  if (!sensor_manager_) {
     callback.Run(nullptr);
     return;
   }
@@ -99,7 +101,7 @@
     // Try to create low-level sensors by default.
     default: {
       base::PostTaskAndReplyWithResult(
-          sensor_thread_->task_runner().get(), FROM_HERE,
+          com_sta_task_runner_.get(), FROM_HERE,
           base::Bind(&PlatformSensorProviderWin::CreateSensorReader,
                      base::Unretained(this), type),
           base::Bind(&PlatformSensorProviderWin::SensorReaderCreated,
@@ -109,27 +111,6 @@
   }
 }
 
-void PlatformSensorProviderWin::FreeResources() {
-  StopSensorThread();
-}
-
-void PlatformSensorProviderWin::CreateSensorThread() {
-  if (!sensor_thread_)
-    sensor_thread_ = std::make_unique<SensorThread>();
-}
-
-bool PlatformSensorProviderWin::StartSensorThread() {
-  CreateSensorThread();
-  if (!sensor_thread_->IsRunning())
-    return sensor_thread_->Start();
-  return true;
-}
-
-void PlatformSensorProviderWin::StopSensorThread() {
-  if (sensor_thread_ && sensor_thread_->IsRunning())
-    sensor_thread_->Stop();
-}
-
 void PlatformSensorProviderWin::SensorReaderCreated(
     mojom::SensorType type,
     SensorReadingSharedBuffer* reading_buffer,
@@ -155,19 +136,18 @@
     }
   }
 
-  scoped_refptr<PlatformSensor> sensor = new PlatformSensorWin(
-      type, reading_buffer, this, sensor_thread_->task_runner(),
-      std::move(sensor_reader));
+  scoped_refptr<PlatformSensor> sensor =
+      new PlatformSensorWin(type, reading_buffer, this, com_sta_task_runner_,
+                            std::move(sensor_reader));
   callback.Run(sensor);
 }
 
 std::unique_ptr<PlatformSensorReaderWin>
 PlatformSensorProviderWin::CreateSensorReader(mojom::SensorType type) {
-  DCHECK(sensor_thread_->task_runner()->BelongsToCurrentThread());
-  if (!sensor_thread_->sensor_manager())
+  DCHECK(com_sta_task_runner_->RunsTasksInCurrentSequence());
+  if (!sensor_manager_)
     return nullptr;
-  return PlatformSensorReaderWin::Create(type,
-                                         sensor_thread_->sensor_manager());
+  return PlatformSensorReaderWin::Create(type, sensor_manager_);
 }
 
 }  // namespace device
diff --git a/services/device/generic_sensor/platform_sensor_provider_win.h b/services/device/generic_sensor/platform_sensor_provider_win.h
index 4b7e1bd..9958ceba 100644
--- a/services/device/generic_sensor/platform_sensor_provider_win.h
+++ b/services/device/generic_sensor/platform_sensor_provider_win.h
@@ -37,7 +37,6 @@
   ~PlatformSensorProviderWin() override;
 
   // PlatformSensorProvider interface implementation.
-  void FreeResources() override;
   void CreateSensorInternal(mojom::SensorType type,
                             SensorReadingSharedBuffer* reading_buffer,
                             const CreateSensorCallback& callback) override;
@@ -45,13 +44,12 @@
  private:
   friend struct base::DefaultSingletonTraits<PlatformSensorProviderWin>;
 
-  class SensorThread;
-
   PlatformSensorProviderWin();
 
-  void CreateSensorThread();
-  bool StartSensorThread();
-  void StopSensorThread();
+  void InitSensorManager();
+  void OnInitSensorManager(mojom::SensorType type,
+                           SensorReadingSharedBuffer* reading_buffer,
+                           const CreateSensorCallback& callback);
   std::unique_ptr<PlatformSensorReaderWin> CreateSensorReader(
       mojom::SensorType type);
   void SensorReaderCreated(
@@ -60,7 +58,8 @@
       const CreateSensorCallback& callback,
       std::unique_ptr<PlatformSensorReaderWin> sensor_reader);
 
-  std::unique_ptr<SensorThread> sensor_thread_;
+  scoped_refptr<base::SingleThreadTaskRunner> com_sta_task_runner_;
+  Microsoft::WRL::ComPtr<ISensorManager> sensor_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(PlatformSensorProviderWin);
 };
diff --git a/services/network/host_resolver.cc b/services/network/host_resolver.cc
index e151eb13..cf52398 100644
--- a/services/network/host_resolver.cc
+++ b/services/network/host_resolver.cc
@@ -12,6 +12,7 @@
 #include "net/base/host_port_pair.h"
 #include "net/base/net_errors.h"
 #include "net/dns/host_resolver.h"
+#include "net/dns/host_resolver_source.h"
 #include "net/log/net_log.h"
 #include "services/network/resolve_host_request.h"
 
@@ -68,6 +69,13 @@
     const net::HostPortPair& host,
     mojom::ResolveHostParametersPtr optional_parameters,
     mojom::ResolveHostClientPtr response_client) {
+#if !BUILDFLAG(ENABLE_MDNS)
+  // TODO(crbug.com/821021): Handle without crashing if we create restricted
+  // HostResolvers for passing to untrusted processes.
+  DCHECK(!optional_parameters ||
+         optional_parameters->source != net::HostResolverSource::MULTICAST_DNS);
+#endif  // !BUILDFLAG(ENABLE_MDNS)
+
   if (resolve_host_callback.Get())
     resolve_host_callback.Get().Run(host.host());
 
diff --git a/services/network/host_resolver_unittest.cc b/services/network/host_resolver_unittest.cc
index 5ea1358..501a042 100644
--- a/services/network/host_resolver_unittest.cc
+++ b/services/network/host_resolver_unittest.cc
@@ -206,6 +206,7 @@
   constexpr char kAnyResult[] = "1.2.3.4";
   constexpr char kSystemResult[] = "127.0.0.1";
   constexpr char kDnsResult[] = "168.100.12.23";
+  constexpr char kMdnsResult[] = "200.1.2.3";
   auto inner_resolver = std::make_unique<net::MockHostResolver>();
   inner_resolver->rules_map()[net::HostResolverSource::ANY]->AddRule(
       kDomain, kAnyResult);
@@ -213,6 +214,8 @@
       kDomain, kSystemResult);
   inner_resolver->rules_map()[net::HostResolverSource::DNS]->AddRule(
       kDomain, kDnsResult);
+  inner_resolver->rules_map()[net::HostResolverSource::MULTICAST_DNS]->AddRule(
+      kDomain, kMdnsResult);
 
   net::NetLog net_log;
   HostResolver resolver(inner_resolver.get(), &net_log);
@@ -258,6 +261,23 @@
   EXPECT_EQ(net::OK, dns_client.result_error());
   EXPECT_THAT(dns_client.result_addresses().value().endpoints(),
               testing::ElementsAre(CreateExpectedEndPoint(kDnsResult, 80)));
+
+#if BUILDFLAG(ENABLE_MDNS)
+  base::RunLoop mdns_run_loop;
+  mojom::ResolveHostClientPtr mdns_client_ptr;
+  TestResolveHostClient mdns_client(&mdns_client_ptr, &mdns_run_loop);
+  mojom::ResolveHostParametersPtr mdns_parameters =
+      mojom::ResolveHostParameters::New();
+  mdns_parameters->source = net::HostResolverSource::MULTICAST_DNS;
+  resolver.ResolveHost(net::HostPortPair(kDomain, 80),
+                       std::move(mdns_parameters), std::move(mdns_client_ptr));
+
+  mdns_run_loop.Run();
+
+  EXPECT_EQ(net::OK, mdns_client.result_error());
+  EXPECT_THAT(mdns_client.result_addresses().value().endpoints(),
+              testing::ElementsAre(CreateExpectedEndPoint(kMdnsResult, 80)));
+#endif  // BUILDFLAG(ENABLE_MDNS)
 }
 
 // Test that cached results are properly keyed by requested source.
diff --git a/services/network/public/cpp/host_resolver_mojom_traits.cc b/services/network/public/cpp/host_resolver_mojom_traits.cc
index 4814649..0364c3e 100644
--- a/services/network/public/cpp/host_resolver_mojom_traits.cc
+++ b/services/network/public/cpp/host_resolver_mojom_traits.cc
@@ -52,6 +52,8 @@
       return ResolveHostParameters::Source::SYSTEM;
     case net::HostResolverSource::DNS:
       return ResolveHostParameters::Source::DNS;
+    case net::HostResolverSource::MULTICAST_DNS:
+      return ResolveHostParameters::Source::MULTICAST_DNS;
   }
 }
 
@@ -69,6 +71,9 @@
     case ResolveHostParameters::Source::DNS:
       *output = net::HostResolverSource::DNS;
       return true;
+    case ResolveHostParameters::Source::MULTICAST_DNS:
+      *output = net::HostResolverSource::MULTICAST_DNS;
+      return true;
   }
 }
 
diff --git a/services/network/public/cpp/network_connection_tracker.h b/services/network/public/cpp/network_connection_tracker.h
index 0f2586a1..a370627 100644
--- a/services/network/public/cpp/network_connection_tracker.h
+++ b/services/network/public/cpp/network_connection_tracker.h
@@ -21,6 +21,12 @@
 
 namespace network {
 
+// Defines the type of a callback that will return a NetworkConnectionTracker
+// instance.
+class NetworkConnectionTracker;
+using NetworkConnectionTrackerGetter =
+    base::RepeatingCallback<NetworkConnectionTracker*()>;
+
 // This class subscribes to network change events from
 // network::mojom::NetworkChangeManager and propogates these notifications to
 // its NetworkConnectionObservers registered through
diff --git a/services/network/public/mojom/host_resolver.mojom b/services/network/public/mojom/host_resolver.mojom
index 769b872..400a9fc 100644
--- a/services/network/public/mojom/host_resolver.mojom
+++ b/services/network/public/mojom/host_resolver.mojom
@@ -65,7 +65,8 @@
     // Results will only come from DNS queries.
     DNS,
 
-    // TODO(crbug.com/846423): Add MDNS support.
+    // Results will only come from Multicast DNS queries.
+    MULTICAST_DNS,
   };
 
   // The source to use for resolved addresses. Default allows the resolver to
diff --git a/services/network/test/test_network_connection_tracker.cc b/services/network/test/test_network_connection_tracker.cc
index cb997d8e..38f2546 100644
--- a/services/network/test/test_network_connection_tracker.cc
+++ b/services/network/test/test_network_connection_tracker.cc
@@ -4,14 +4,23 @@
 
 #include "services/network/test/test_network_connection_tracker.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 
 namespace network {
 
 static TestNetworkConnectionTracker* g_test_network_connection_tracker_instance;
 
+namespace {
+
+NetworkConnectionTracker* GetNonTestInstance() {
+  return TestNetworkConnectionTracker::GetInstance();
+}
+
+}  // namespace
+
 // static
 std::unique_ptr<TestNetworkConnectionTracker>
 TestNetworkConnectionTracker::CreateInstance() {
@@ -24,6 +33,11 @@
   return g_test_network_connection_tracker_instance;
 }
 
+// static
+NetworkConnectionTrackerGetter TestNetworkConnectionTracker::CreateGetter() {
+  return base::BindRepeating(&GetNonTestInstance);
+}
+
 TestNetworkConnectionTracker::TestNetworkConnectionTracker() {
   if (g_test_network_connection_tracker_instance) {
     LOG(WARNING) << "Creating more than one TestNetworkConnectionTracker";
diff --git a/services/network/test/test_network_connection_tracker.h b/services/network/test/test_network_connection_tracker.h
index dfefe5e..72d31355 100644
--- a/services/network/test/test_network_connection_tracker.h
+++ b/services/network/test/test_network_connection_tracker.h
@@ -25,6 +25,10 @@
   // CreateInstance() must have been called before calling this.
   static TestNetworkConnectionTracker* GetInstance();
 
+  // Creates a NetworkConnectionTrackerGetter that will return the active
+  // TestNetworkConnectionTracker instance when called.
+  static NetworkConnectionTrackerGetter CreateGetter();
+
   ~TestNetworkConnectionTracker() override;
 
   bool GetConnectionType(network::mojom::ConnectionType* type,
diff --git a/services/tracing/perfetto/json_trace_exporter_unittest.cc b/services/tracing/perfetto/json_trace_exporter_unittest.cc
index ff783b9..f46987d1 100644
--- a/services/tracing/perfetto/json_trace_exporter_unittest.cc
+++ b/services/tracing/perfetto/json_trace_exporter_unittest.cc
@@ -70,7 +70,6 @@
     mock_service_->OnTracingEnabled(
         config.data_sources()[0].config().chrome_config().trace_config());
   }
-
   void DisableTracing() override { mock_service_->OnTracingDisabled(); }
   void ReadBuffers() override {}
   void FreeBuffers() override {}
@@ -78,6 +77,9 @@
     callback(true);
   }
 
+  // Unused in chrome, only meaningful when using TraceConfig.deferred_start.
+  void StartTracing() override {}
+
  private:
   MockService* mock_service_;
 };
diff --git a/services/tracing/perfetto/producer_host.cc b/services/tracing/perfetto/producer_host.cc
index bc4fc15..470fac6 100644
--- a/services/tracing/perfetto/producer_host.cc
+++ b/services/tracing/perfetto/producer_host.cc
@@ -71,6 +71,11 @@
   producer_client_->OnTracingStart(std::move(shm));
 }
 
+void ProducerHost::SetupDataSource(perfetto::DataSourceInstanceID,
+                                   const perfetto::DataSourceConfig&) {
+  // TODO(primiano): plumb call through mojo.
+}
+
 void ProducerHost::StartDataSource(perfetto::DataSourceInstanceID id,
                                    const perfetto::DataSourceConfig& config) {
   // TODO(oysteine): Send full DataSourceConfig, not just the name/target_buffer
diff --git a/services/tracing/perfetto/producer_host.h b/services/tracing/perfetto/producer_host.h
index 05367bf9..5a477c1 100644
--- a/services/tracing/perfetto/producer_host.h
+++ b/services/tracing/perfetto/producer_host.h
@@ -60,6 +60,9 @@
   void OnConnect() override;
   void OnDisconnect() override;
 
+  void SetupDataSource(perfetto::DataSourceInstanceID id,
+                       const perfetto::DataSourceConfig& config) override;
+
   void StartDataSource(perfetto::DataSourceInstanceID id,
                        const perfetto::DataSourceConfig& config) override;
 
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.cc b/services/video_capture/device_factory_media_to_mojo_adapter.cc
index 36d2c712..63bca2d 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -77,12 +77,10 @@
     DeviceFactoryMediaToMojoAdapter::ActiveDeviceEntry&& other) = default;
 
 DeviceFactoryMediaToMojoAdapter::DeviceFactoryMediaToMojoAdapter(
-    std::unique_ptr<service_manager::ServiceContextRef> service_ref,
     std::unique_ptr<media::VideoCaptureSystem> capture_system,
     media::MojoJpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_callback,
     scoped_refptr<base::SequencedTaskRunner> jpeg_decoder_task_runner)
-    : service_ref_(std::move(service_ref)),
-      capture_system_(std::move(capture_system)),
+    : capture_system_(std::move(capture_system)),
       jpeg_decoder_factory_callback_(std::move(jpeg_decoder_factory_callback)),
       jpeg_decoder_task_runner_(std::move(jpeg_decoder_task_runner)),
       has_called_get_device_infos_(false),
@@ -90,6 +88,11 @@
 
 DeviceFactoryMediaToMojoAdapter::~DeviceFactoryMediaToMojoAdapter() = default;
 
+void DeviceFactoryMediaToMojoAdapter::SetServiceRef(
+    std::unique_ptr<service_manager::ServiceContextRef> service_ref) {
+  service_ref_ = std::move(service_ref);
+}
+
 void DeviceFactoryMediaToMojoAdapter::GetDeviceInfos(
     GetDeviceInfosCallback callback) {
   capture_system_->GetDeviceInfosAsync(
@@ -129,6 +132,7 @@
   capture_system_->GetDeviceInfosAsync(
       base::Bind(&DiscardDeviceInfosAndCallContinuation,
                  base::Passed(&create_and_add_new_device_cb)));
+  has_called_get_device_infos_ = true;
 }
 
 void DeviceFactoryMediaToMojoAdapter::AddSharedMemoryVirtualDevice(
@@ -154,6 +158,7 @@
     const std::string& device_id,
     mojom::DeviceRequest device_request,
     CreateDeviceCallback callback) {
+  DCHECK(service_ref_);
   std::unique_ptr<media::VideoCaptureDevice> media_device =
       capture_system_->CreateDevice(device_id);
   if (media_device == nullptr) {
diff --git a/services/video_capture/device_factory_media_to_mojo_adapter.h b/services/video_capture/device_factory_media_to_mojo_adapter.h
index 0c785b7..1f09720 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.h
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -24,12 +24,14 @@
 class DeviceFactoryMediaToMojoAdapter : public mojom::DeviceFactory {
  public:
   DeviceFactoryMediaToMojoAdapter(
-      std::unique_ptr<service_manager::ServiceContextRef> service_ref,
       std::unique_ptr<media::VideoCaptureSystem> capture_system,
       media::MojoJpegDecodeAcceleratorFactoryCB jpeg_decoder_factory_callback,
       scoped_refptr<base::SequencedTaskRunner> jpeg_decoder_task_runner);
   ~DeviceFactoryMediaToMojoAdapter() override;
 
+  void SetServiceRef(
+      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+
   // mojom::DeviceFactory implementation.
   void GetDeviceInfos(GetDeviceInfosCallback callback) override;
   void CreateDevice(const std::string& device_id,
@@ -65,7 +67,7 @@
                              CreateDeviceCallback callback);
   void OnClientConnectionErrorOrClose(const std::string& device_id);
 
-  const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
+  std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
   const std::unique_ptr<media::VideoCaptureSystem> capture_system_;
   const media::MojoJpegDecodeAcceleratorFactoryCB
       jpeg_decoder_factory_callback_;
diff --git a/services/video_capture/device_factory_provider_impl.cc b/services/video_capture/device_factory_provider_impl.cc
index b62f196..1e0176b 100644
--- a/services/video_capture/device_factory_provider_impl.cc
+++ b/services/video_capture/device_factory_provider_impl.cc
@@ -67,9 +67,13 @@
   base::WeakPtrFactory<GpuDependenciesContext> weak_factory_for_gpu_io_thread_;
 };
 
-DeviceFactoryProviderImpl::DeviceFactoryProviderImpl(
-    std::unique_ptr<service_manager::ServiceContextRef> service_ref)
-    : service_ref_(std::move(service_ref)) {}
+DeviceFactoryProviderImpl::DeviceFactoryProviderImpl() {
+  // Unretained |this| is safe because |factory_bindings_| is owned by
+  // |this|.
+  factory_bindings_.set_connection_error_handler(base::BindRepeating(
+      &DeviceFactoryProviderImpl::OnFactoryClientDisconnected,
+      base::Unretained(this)));
+}
 
 DeviceFactoryProviderImpl::~DeviceFactoryProviderImpl() {
   factory_bindings_.CloseAllBindings();
@@ -80,6 +84,11 @@
   }
 }
 
+void DeviceFactoryProviderImpl::SetServiceRef(
+    std::unique_ptr<service_manager::ServiceContextRef> service_ref) {
+  service_ref_ = std::move(service_ref);
+}
+
 void DeviceFactoryProviderImpl::InjectGpuDependencies(
     mojom::AcceleratorFactoryPtr accelerator_factory) {
   LazyInitializeGpuDependenciesContext();
@@ -91,7 +100,10 @@
 
 void DeviceFactoryProviderImpl::ConnectToDeviceFactory(
     mojom::DeviceFactoryRequest request) {
+  DCHECK(service_ref_);
   LazyInitializeDeviceFactory();
+  if (factory_bindings_.empty())
+    device_factory_->SetServiceRef(service_ref_->Clone());
   factory_bindings_.AddBinding(device_factory_.get(), std::move(request));
 }
 
@@ -119,13 +131,22 @@
       std::move(media_device_factory));
 
   device_factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>(
-      service_ref_->Clone(),
       std::make_unique<DeviceFactoryMediaToMojoAdapter>(
-          service_ref_->Clone(), std::move(video_capture_system),
+          std::move(video_capture_system),
           base::BindRepeating(
               &GpuDependenciesContext::CreateJpegDecodeAccelerator,
               gpu_dependencies_context_->GetWeakPtr()),
           gpu_dependencies_context_->GetTaskRunner()));
 }
 
+void DeviceFactoryProviderImpl::OnFactoryClientDisconnected() {
+  // If last client has disconnected, release service ref so that service
+  // shutdown timeout starts if no other references are still alive.
+  // We keep the |device_factory_| instance alive in order to avoid
+  // losing state that would be expensive to reinitialize, e.g. having
+  // already enumerated the available devices.
+  if (factory_bindings_.empty())
+    device_factory_->SetServiceRef(nullptr);
+}
+
 }  // namespace video_capture
diff --git a/services/video_capture/device_factory_provider_impl.h b/services/video_capture/device_factory_provider_impl.h
index ee9119c6..b0609b4c 100644
--- a/services/video_capture/device_factory_provider_impl.h
+++ b/services/video_capture/device_factory_provider_impl.h
@@ -17,12 +17,16 @@
 
 namespace video_capture {
 
+class VirtualDeviceEnabledDeviceFactory;
+
 class DeviceFactoryProviderImpl : public mojom::DeviceFactoryProvider {
  public:
-  DeviceFactoryProviderImpl(
-      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+  DeviceFactoryProviderImpl();
   ~DeviceFactoryProviderImpl() override;
 
+  void SetServiceRef(
+      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+
   // mojom::DeviceFactoryProvider implementation.
   void InjectGpuDependencies(
       mojom::AcceleratorFactoryPtr accelerator_factory) override;
@@ -33,10 +37,11 @@
 
   void LazyInitializeGpuDependenciesContext();
   void LazyInitializeDeviceFactory();
+  void OnFactoryClientDisconnected();
 
   mojo::BindingSet<mojom::DeviceFactory> factory_bindings_;
-  std::unique_ptr<mojom::DeviceFactory> device_factory_;
-  const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
+  std::unique_ptr<VirtualDeviceEnabledDeviceFactory> device_factory_;
+  std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
   std::unique_ptr<GpuDependenciesContext> gpu_dependencies_context_;
 
   DISALLOW_COPY_AND_ASSIGN(DeviceFactoryProviderImpl);
diff --git a/services/video_capture/service_impl.cc b/services/video_capture/service_impl.cc
index 52d58ca..9c981ae 100644
--- a/services/video_capture/service_impl.cc
+++ b/services/video_capture/service_impl.cc
@@ -79,6 +79,8 @@
       base::Bind(&ServiceImpl::OnTestingControlsRequest,
                  base::Unretained(this)));
 
+  // Unretained |this| is safe because |factory_provider_bindings_| is owned by
+  // |this|.
   factory_provider_bindings_.set_connection_error_handler(base::BindRepeating(
       &ServiceImpl::OnProviderClientDisconnected, base::Unretained(this)));
 }
@@ -112,6 +114,8 @@
     mojom::DeviceFactoryProviderRequest request) {
   DCHECK(thread_checker_.CalledOnValidThread());
   LazyInitializeDeviceFactoryProvider();
+  if (factory_provider_bindings_.empty())
+    device_factory_provider_->SetServiceRef(ref_factory_->CreateRef());
   factory_provider_bindings_.AddBinding(device_factory_provider_.get(),
                                         std::move(request));
 
@@ -132,15 +136,17 @@
   if (device_factory_provider_)
     return;
 
-  device_factory_provider_ =
-      std::make_unique<DeviceFactoryProviderImpl>(ref_factory_->CreateRef());
+  device_factory_provider_ = std::make_unique<DeviceFactoryProviderImpl>();
 }
 
 void ServiceImpl::OnProviderClientDisconnected() {
-  // Reset factory provider if no client is connected.
-  if (factory_provider_bindings_.empty()) {
-    device_factory_provider_.reset();
-  }
+  // If last client has disconnected, release service ref so that service
+  // shutdown timeout starts if no other references are still alive.
+  // We keep the |device_factory_provider_| instance alive in order to avoid
+  // losing state that would be expensive to reinitialize, e.g. having
+  // already enumerated the available devices.
+  if (factory_provider_bindings_.empty())
+    device_factory_provider_->SetServiceRef(nullptr);
 
   if (!factory_provider_client_disconnected_cb_.is_null()) {
     factory_provider_client_disconnected_cb_.Run();
diff --git a/services/video_capture/test/mock_device_test.cc b/services/video_capture/test/mock_device_test.cc
index 1d1cca2..eaa3bf5b 100644
--- a/services/video_capture/test/mock_device_test.cc
+++ b/services/video_capture/test/mock_device_test.cc
@@ -31,8 +31,9 @@
       std::move(mock_device_factory));
   mock_device_factory_adapter_ =
       std::make_unique<DeviceFactoryMediaToMojoAdapter>(
-          ref_factory_.CreateRef(), std::move(video_capture_system),
-          base::DoNothing(), base::ThreadTaskRunnerHandle::Get());
+          std::move(video_capture_system), base::DoNothing(),
+          base::ThreadTaskRunnerHandle::Get());
+  mock_device_factory_adapter_->SetServiceRef(ref_factory_.CreateRef());
 
   mock_factory_binding_ = std::make_unique<mojo::Binding<mojom::DeviceFactory>>(
       mock_device_factory_adapter_.get(), mojo::MakeRequest(&factory_));
diff --git a/services/video_capture/virtual_device_enabled_device_factory.cc b/services/video_capture/virtual_device_enabled_device_factory.cc
index 092faff..4675957fb 100644
--- a/services/video_capture/virtual_device_enabled_device_factory.cc
+++ b/services/video_capture/virtual_device_enabled_device_factory.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "media/capture/video/video_capture_device_info.h"
+#include "services/video_capture/device_factory_media_to_mojo_adapter.h"
 #include "services/video_capture/shared_memory_virtual_device_mojo_adapter.h"
 #include "services/video_capture/texture_virtual_device_mojo_adapter.h"
 
@@ -84,15 +85,21 @@
 };
 
 VirtualDeviceEnabledDeviceFactory::VirtualDeviceEnabledDeviceFactory(
-    std::unique_ptr<service_manager::ServiceContextRef> service_ref,
-    std::unique_ptr<mojom::DeviceFactory> device_factory)
-    : service_ref_(std::move(service_ref)),
-      device_factory_(std::move(device_factory)),
-      weak_factory_(this) {}
+    std::unique_ptr<DeviceFactoryMediaToMojoAdapter> device_factory)
+    : device_factory_(std::move(device_factory)), weak_factory_(this) {}
 
 VirtualDeviceEnabledDeviceFactory::~VirtualDeviceEnabledDeviceFactory() =
     default;
 
+void VirtualDeviceEnabledDeviceFactory::SetServiceRef(
+    std::unique_ptr<service_manager::ServiceContextRef> service_ref) {
+  if (service_ref)
+    device_factory_->SetServiceRef(service_ref->Clone());
+  else
+    device_factory_->SetServiceRef(nullptr);
+  service_ref_ = std::move(service_ref);
+}
+
 void VirtualDeviceEnabledDeviceFactory::GetDeviceInfos(
     GetDeviceInfosCallback callback) {
   device_factory_->GetDeviceInfos(
diff --git a/services/video_capture/virtual_device_enabled_device_factory.h b/services/video_capture/virtual_device_enabled_device_factory.h
index f753c00ca..b40f3a9 100644
--- a/services/video_capture/virtual_device_enabled_device_factory.h
+++ b/services/video_capture/virtual_device_enabled_device_factory.h
@@ -15,15 +15,19 @@
 
 namespace video_capture {
 
+class DeviceFactoryMediaToMojoAdapter;
+
 // Decorator that adds support for virtual devices to a given
 // mojom::DeviceFactory.
 class VirtualDeviceEnabledDeviceFactory : public mojom::DeviceFactory {
  public:
-  VirtualDeviceEnabledDeviceFactory(
-      std::unique_ptr<service_manager::ServiceContextRef> service_ref,
-      std::unique_ptr<mojom::DeviceFactory> factory);
+  explicit VirtualDeviceEnabledDeviceFactory(
+      std::unique_ptr<DeviceFactoryMediaToMojoAdapter> factory);
   ~VirtualDeviceEnabledDeviceFactory() override;
 
+  void SetServiceRef(
+      std::unique_ptr<service_manager::ServiceContextRef> service_ref);
+
   // mojom::DeviceFactory implementation.
   void GetDeviceInfos(GetDeviceInfosCallback callback) override;
   void CreateDevice(const std::string& device_id,
@@ -56,8 +60,8 @@
       mojom::DevicesChangedObserverPtr* observer);
 
   std::map<std::string, VirtualDeviceEntry> virtual_devices_by_id_;
-  const std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
-  const std::unique_ptr<mojom::DeviceFactory> device_factory_;
+  const std::unique_ptr<DeviceFactoryMediaToMojoAdapter> device_factory_;
+  std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
   std::vector<mojom::DevicesChangedObserverPtr> devices_changed_observers_;
 
   base::WeakPtrFactory<VirtualDeviceEnabledDeviceFactory> weak_factory_;
diff --git a/services/ws/public/mojom/window_manager.mojom b/services/ws/public/mojom/window_manager.mojom
index 8183d651..6a30b3b3 100644
--- a/services/ws/public/mojom/window_manager.mojom
+++ b/services/ws/public/mojom/window_manager.mojom
@@ -78,6 +78,11 @@
   // "com.google.Photos". Type: mojom::String.
   const string kArcPackageName_Property = "prop:arc-package-name";
 
+  // The accessibility ui::AXTreeID for a views::Widget.
+  // TODO(dmazzoni): Convert to base::UnguessableToken. https://crbug.com/881986
+  // Type: mojom::String
+  const string kChildAXTreeID_Property = "prop:child-ax-tree-id";
+
   // The modal parent of a child modal window. Type: window Id.
   const string kChildModalParent_Property = "prop:child-modal-parent";
 
diff --git a/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter b/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter
index 92beb72..44bab77 100644
--- a/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter
+++ b/testing/buildbot/filters/mojo.fyi.chromeos.network_browser_tests.filter
@@ -7,26 +7,17 @@
 # See https://crbug.com/881976
 
 # Uncategorized timeouts or test failures.
--AffiliationCheck/EnterpriseDeviceAttributesTest.Success/Affiliated
--AffiliationCheck/EnterpriseDeviceAttributesTest.Success/NotAffiliated
--BackgroundFetchBrowserTest.FetchCanBePausedAndResumed
--CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/0
--CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/1
--CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/2
--CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/3
--ChromeNewWindowClientBrowserTest.NewWindowForActiveWindowProfileTest
+-PolicyProvidedTrustAnchorsRegularUserTest.AllowedForRegularUser
+-ForceMaximizeOnFirstRunTest.TwoRuns
+-ForceMaximizePolicyFalseTest.GeneralFirstRun
+
+# Stuck at the 'Local Auth Server' screen with email / password filed. Some
+# tests will pass after clicking 'Next' manually, while others may fail later
+# due to other issues such as empty |device_id_in_profile|.
 -ChromeSessionManagerTest.OobeNewUser
 -DeviceIDTest.LegacyUsers
 -DeviceIDTest.Migration
 -DeviceIDTest.NewUsers
--ExtensionWebRequestApiTest.WebRequestApiDoesNotCrashOnErrorAfterProfileDestroyed
--ForceMaximizeOnFirstRunTest.TwoRuns
--ForceMaximizePolicyFalseTest.GeneralFirstRun
--HostedAppNonClientFrameViewAshTest.FocusableViews/material
--HostedAppNonClientFrameViewAshTest.FocusableViews/material_refresh
--HostedAppNonClientFrameViewAshTest.FocusableViews/material_refresh_touch_optimized
--HostedAppNonClientFrameViewAshTest.FocusableViews/material_touch_optimized
--KioskUpdateTest.LaunchCachedOfflineEnabledAppNoNetwork
 -LoginPolicyTestBase.AllowedInputMethods
 -LoginPolicyTestBase.AllowedUILocales
 -MergeSessionTest.PageThrottle
@@ -36,7 +27,20 @@
 -OAuth2Test.VerifyInAdvancedProtectionAfterOnlineAuth
 -OAuth2Test.VerifyNotInAdvancedProtectionAfterOnlineAuth
 -PolicyProvidedTrustAnchorsOnUserSessionInitTest.TrustAnchorsAvailableImmediatelyAfterSessionStart
--PolicyProvidedTrustAnchorsRegularUserTest.AllowedForRegularUser
+-UserCloudExternalDataManagerTest.FetchExternalData
+-UserCloudPolicyManagerChildTest.PolicyForChildUser
+-UserCloudPolicyManagerNonEnterpriseTest.NoPolicyForConsumer
+-UserCloudPolicyManagerTest.ErrorLoadingPolicy
+-UserCloudPolicyManagerTest.ErrorLoadingPolicyForUnmanagedUser
+-UserCloudPolicyManagerTest.MigrateForExistingUser
+-UserCloudPolicyManagerTest.StartSession
+-WebviewLoginTest.Basic
+
+# The test went into the 'Local Auth Server' screen instead of the Kiosk screen.
+-KioskUpdateTest.LaunchCachedOfflineEnabledAppNoNetwork
+
+# SAML doesn't work with Network Service.
+# https://crbug.com/887061
 -SAMLPolicyTest.NoSAML
 -SAMLPolicyTest.SAMLNoLimit
 -SAMLPolicyTest.SAMLZeroLimit
@@ -48,6 +52,67 @@
 -SamlTest.ScrapedNone
 -SamlTest.ScrapedSingle
 -SamlTest.UseAutenticatedUserEmailAddress
+-ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowFailsError
+-ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowFailsUserCancelled
+-ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowSucceedsWithAuthRetry
+-ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowSucceedsWithDmRetry
+-ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowSuccess
+
+# |NetworkChangeNotifier()| Not implemented.
+# https://crbug.com/882610
+-ChromeBrowserMainBrowserTest.VariationsServiceStartsRequestOnNetworkChange
+-NetworkConnectionTrackerBrowserTest.SimulateNetworkServiceCrash
+-BackgroundFetchBrowserTest.FetchCanBePausedAndResumed
+-BackgroundFetchBrowserTest.FetchesRunToCompletionAndUpdateTitle_Failed
+-BackgroundFetchBrowserTest.FetchesRunToCompletionAndUpdateTitle_Fetched
+-BackgroundFetchBrowserTest.FetchFromChildFrameWithPermissions
+-BackgroundFetchBrowserTest.FetchFromServiceWorker
+-BackgroundFetchBrowserTest.OfflineItemCollection_VerifyResourceDownloadedWhenDownloadTotalLargerThanActualSize
+-BackgroundFetchBrowserTest.OfflineItemCollection_VerifyResourceDownloadedWhenDownloadTotalSmallerThanActualSize
+
+# Stuck at 'Network not available' page, should be related to the
+# |NetworkChangeNotifier()| issue.
+# https://crbug.com/882610
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/0
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/1
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/10
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/11
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/2
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/3
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/4
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/5
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/6
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/7
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/8
+-SiteIsolationFlagHandlingTest.FlagHandlingTest/9
+-WizardControllerDeviceStateExplicitRequirement/WizardControllerDeviceStateExplicitRequirementTest.ControlFlowForcedReEnrollment/0
+-WizardControllerDeviceStateExplicitRequirement/WizardControllerDeviceStateExplicitRequirementTest.ControlFlowForcedReEnrollment/1
+-WizardControllerDeviceStateTest.ControlFlowDeviceDisabled
+-WizardControllerDeviceStateWithInitialEnrollmentTest.ControlFlowInitialEnrollment
+
+# Convert from policy::TestRequestInterceptor to network::TestURLLoaderFactory.
+# See https://chromium-review.googlesource.com/c/chromium/src/+/1113029 for
+# examples.
+-ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.ArcDisabled
+-ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.RequestAccountInfoSuccess
+-ArcRobotAuthCodeFetcherBrowserTest.RequestAccountInfoError
+-ArcRobotAuthCodeFetcherBrowserTest.RequestAccountInfoSuccess
+-ArcRobotAccountAuthServiceTest.GetDemoAccount
+-ArcRobotAccountAuthServiceTest.GetDemoAccountOnAuthTokenFetchFailure
+
+# Relies on net::URLRequestInterceptor.
+# https://crbug.com/884782
+# Convert the production code using example of how we add/remove
+# variations::kClientDataHeader in GoogleURLLoaderThrottle.
+-ChromeResourceDispatcherHostDelegateMirrorBrowserTest.MirrorRequestHeader
+
+# Relies on net::URLRequestMockHTTPJob.
+-AffiliationCheck/EnterpriseDeviceAttributesTest.Success/Affiliated
+-AffiliationCheck/EnterpriseDeviceAttributesTest.Success/NotAffiliated
+-CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/0
+-CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/1
+-CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/2
+-CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/3
 -SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/0
 -SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/1
 -SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/2
@@ -65,56 +130,14 @@
 -SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/4
 -SigninProfileAppsPolicyTest.BackgroundPage
 -SigninProfileAppsPolicyTest.MultipleApps
--SiteIsolationFlagHandlingTest.FlagHandlingTest/0
--SiteIsolationFlagHandlingTest.FlagHandlingTest/1
--SiteIsolationFlagHandlingTest.FlagHandlingTest/10
--SiteIsolationFlagHandlingTest.FlagHandlingTest/11
--SiteIsolationFlagHandlingTest.FlagHandlingTest/2
--SiteIsolationFlagHandlingTest.FlagHandlingTest/3
--SiteIsolationFlagHandlingTest.FlagHandlingTest/4
--SiteIsolationFlagHandlingTest.FlagHandlingTest/5
--SiteIsolationFlagHandlingTest.FlagHandlingTest/6
--SiteIsolationFlagHandlingTest.FlagHandlingTest/7
--SiteIsolationFlagHandlingTest.FlagHandlingTest/8
--SiteIsolationFlagHandlingTest.FlagHandlingTest/9
--UserCloudExternalDataManagerTest.FetchExternalData
--UserCloudPolicyManagerChildTest.PolicyForChildUser
--UserCloudPolicyManagerNonEnterpriseTest.NoPolicyForConsumer
--UserCloudPolicyManagerTest.ErrorLoadingPolicy
--UserCloudPolicyManagerTest.ErrorLoadingPolicyForUnmanagedUser
--UserCloudPolicyManagerTest.MigrateForExistingUser
--UserCloudPolicyManagerTest.StartSession
--WebviewLoginTest.Basic
--WizardControllerDeviceStateExplicitRequirement/WizardControllerDeviceStateExplicitRequirementTest.ControlFlowForcedReEnrollment/0
--WizardControllerDeviceStateExplicitRequirement/WizardControllerDeviceStateExplicitRequirementTest.ControlFlowForcedReEnrollment/1
--WizardControllerDeviceStateTest.ControlFlowDeviceDisabled
--WizardControllerDeviceStateWithInitialEnrollmentTest.ControlFlowInitialEnrollment
 
-# NetworkChangeNotifier() Not implemented.
-# https://crbug.com/882610
--ChromeBrowserMainBrowserTest.VariationsServiceStartsRequestOnNetworkChange
--NetworkConnectionTrackerBrowserTest.SimulateNetworkServiceCrash
--BackgroundFetchBrowserTest.FetchesRunToCompletionAndUpdateTitle_Failed
--BackgroundFetchBrowserTest.FetchesRunToCompletionAndUpdateTitle_Fetched
--BackgroundFetchBrowserTest.FetchFromChildFrameWithPermissions
--BackgroundFetchBrowserTest.FetchFromServiceWorker
--BackgroundFetchBrowserTest.OfflineItemCollection_VerifyResourceDownloadedWhenDownloadTotalLargerThanActualSize
--BackgroundFetchBrowserTest.OfflineItemCollection_VerifyResourceDownloadedWhenDownloadTotalSmallerThanActualSize
+# Navigation blocked by Safe Browsing.
+# e.g. Showing 'Your connection is not private' instead of opening 'app.com'.
+-HostedAppNonClientFrameViewAshTest.FocusableViews/material_refresh
+-HostedAppNonClientFrameViewAshTest.FocusableViews/material_refresh_touch_optimized
 
-# Relies on net::URLRequestInterceptor.
-# https://crbug.com/884782
--ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.ArcDisabled
--ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.RequestAccountInfoSuccess
--ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowFailsError
--ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowFailsUserCancelled
--ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowSucceedsWithAuthRetry
--ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowSucceedsWithDmRetry
--ArcActiveDirectoryEnrollmentTokenFetcherBrowserTest.SamlFlowSuccess
--ArcRobotAccountAuthServiceTest.GetDemoAccount
--ArcRobotAccountAuthServiceTest.GetDemoAccountOnAuthTokenFetchFailure
--ArcRobotAuthCodeFetcherBrowserTest.RequestAccountInfoError
--ArcRobotAuthCodeFetcherBrowserTest.RequestAccountInfoSuccess
--ChromeResourceDispatcherHostDelegateMirrorBrowserTest.MirrorRequestHeader
+# Failed with error: `profile_impl.cc(469)] Check failed: user`.
+-ExtensionWebRequestApiTest.WebRequestApiDoesNotCrashOnErrorAfterProfileDestroyed
 
 # Flaky with error: `Check failed: (sequence_checker_).CalledOnValidSequence()`.
 -DevToolsSanityTest.DisposeEmptyBrowserContext
diff --git a/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter b/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter
index 9e18bd2..d3325992 100644
--- a/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter
+++ b/testing/buildbot/filters/mojo.fyi.network_chrome_public_test_apk.filter
@@ -12,11 +12,6 @@
 -org.chromium.chrome.browser.FeaturesAnnotationsTest.testFeaturesDoNotRemoveExistingFlags
 -org.chromium.chrome.browser.FeaturesAnnotationsTest.testFeaturesSetExistingFlags
 
-# http://crbug.com/882019
--org.chromium.chrome.browser.UrlSchemeTest.testContentUrlAccess
--org.chromium.chrome.browser.UrlSchemeTest.testContentUrlIframeAccessFromContentUrl
--org.chromium.chrome.browser.UrlSchemeTest.testContentUrlImageFromContentUrl
-
 # https://crbug.com/721403
 -org.chromium.chrome.browser.TabsOpenedFromExternalAppTest.testLaunchWebLiteURL
 -org.chromium.chrome.browser.appmenu.DataSaverAppMenuTest.testMenuDataSaver
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 6cecea8d..73e9992 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -643,7 +643,13 @@
     ],
     "AutofillPreviewStyleExperiment": [
         {
-            "platforms": [],
+            "platforms": [
+                "android",
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
             "experiments": [
                 {
                     "name": "Enabled_BlackOnGoogleBlue050_V2",
@@ -668,6 +674,36 @@
             ]
         }
     ],
+    "AutofillPrimaryInfoStyleExperiment": [
+        {
+            "platforms": [
+                "chromeos",
+                "linux",
+                "mac",
+                "windows"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled_medium",
+                    "params": {
+                        "font_weight": "medium"
+                    },
+                    "enable_features": [
+                        "AutofillPrimaryInfoStyleExperiment"
+                    ]
+                },
+                {
+                    "name": "Enabled_bold",
+                    "params": {
+                        "font_weight": "bold"
+                    },
+                    "enable_features": [
+                        "AutofillPrimaryInfoStyleExperiment"
+                    ]
+                }
+            ]
+        }
+    ],
     "AutofillResetFullServerCardsOnAuthError": [
         {
             "platforms": [
@@ -2517,8 +2553,7 @@
                     "enable_features": [
                         "NewTabPageBackgrounds",
                         "NewTabPageCustomLinks",
-                        "NewTabPageIcons",
-                        "NewTabPageUIMd"
+                        "NewTabPageIcons"
                     ]
                 }
             ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
index b3f27ac2b..2ea7da2 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
@@ -201,10 +201,6 @@
 Bug(none) virtual/prefer_compositing_to_lcd_text/compositing/overflow/scaled-overflow.html [ Failure ]
 Bug(none) compositing/overflow/scaled-overflow.html [ Failure ]
 
-# Incorrect clipping.
-crbug.com/879173 compositing/overflow/nested-render-surfaces-with-rotation.html [ Failure ]
-crbug.com/879173 virtual/prefer_compositing_to_lcd_text/compositing/overflow/nested-render-surfaces-with-rotation.html [ Failure ]
-
 # Incorrect scrollbar invalidation.
 crbug.com/887000 virtual/prefer_compositing_to_lcd_text/scrollbars/hidden-scrollbars-invisible.html [ Failure ]
 
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 607089e..45cdb148 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2314,6 +2314,8 @@
 crbug.com/806357 [ Win Debug ] virtual/threaded/fast/events/pointerevents/pinch/pointerevent_touch-action-pinch_zoom_touch.html [ Pass Failure ]
 crbug.com/839038 [ Mac ] external/wpt/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html [ Skip ]
 
+crbug.com/869919 external/wpt/uievents/click/click_event_target-manual.html [ Failure ]
+
 crbug.com/346473  fast/events/drag-on-mouse-move-cancelled.html [ Failure ]
 crbug.com/346473  virtual/mouseevent_fractional/fast/events/drag-on-mouse-move-cancelled.html [ Failure ]
 crbug.com/346473  virtual/user-activation-v2/fast/events/drag-on-mouse-move-cancelled.html [ Failure ]
@@ -2646,6 +2648,7 @@
 crbug.com/654477 [ Win ] compositing/video/video-controls-layer-creation.html [ Pass Failure ]
 crbug.com/654477 fast/hidpi/video-controls-in-hidpi.html [ Failure ]
 crbug.com/654477 fast/layers/video-layer.html [ Failure ]
+# These could likely be removed - see https://chromium-review.googlesource.com/c/chromium/src/+/1252141
 crbug.com/654477 media/controls-focus-ring.html [ Failure ]
 crbug.com/654477 virtual/video-surface-layer/media/controls-focus-ring.html [ Failure ]
 crbug.com/654477 [ Mac10.10 Mac10.11 Retina ] http/tests/media/video-buffered-range-contains-currentTime.html [ Failure ]
@@ -2824,7 +2827,6 @@
 crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/align_center_position_lt_50_size_gt_maximum_size.html [ Failure ]
 crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/align_center.html [ Failure ]
 crbug.com/626703 external/wpt/webvtt/rendering/cues-with-video/processing-model/regions/viewportanchor_y_50_percent.html [ Timeout ]
-crbug.com/626703 external/wpt/css/css-masking/mask-svg-content/mask-text-001.svg [ Failure ]
 crbug.com/626703 external/wpt/css/css-backgrounds/border-image-width-008.html [ Failure ]
 crbug.com/626703 external/wpt/content-security-policy/generic/only-valid-whitespaces-are-allowed.html [ Timeout ]
 crbug.com/626703 virtual/outofblink-cors-ns/external/wpt/referrer-policy/css-integration/svg/internal-stylesheet.html [ Timeout ]
@@ -3988,10 +3990,6 @@
 # Crashes
 crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Crash Pass ]
 
-# ====== Tests from enabling .any.js/.worker.js tests end here ========
-
-crbug.com/789139 http/tests/devtools/sources/debugger/live-edit-no-reveal.js [ Failure Pass Timeout Crash ]
-
 # ====== Begin of display: contents tests ======
 
 crbug.com/795217 external/wpt/css/css-display/display-contents-details.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
index 83c7783..4ef0a77 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
@@ -434227,7 +434227,7 @@
    "support"
   ],
   "webxr/resources/webxr_util.js": [
-   "d73cf8d44e902b57d4b79fd8d8f68251be7f88a4",
+   "5437513b304cb517a67c8e13f6137759d87156be",
    "support"
   ],
   "webxr/webGLCanvasContext_create_with_xrdevice.https.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/accelerometer/Accelerometer-iframe-access.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/accelerometer/Accelerometer-iframe-access.https-expected.txt
index e2983007..af69542d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/accelerometer/Accelerometer-iframe-access.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/accelerometer/Accelerometer-iframe-access.https-expected.txt
@@ -1,9 +1,12 @@
 This is a testharness.js-based test.
 PASS Accelerometer: sensor is suspended and resumed when focus traverses from to cross-origin frame
 PASS Accelerometer: sensor is not suspended when focus traverses from to same-origin frame
+PASS Accelerometer: losing a document's frame with an active sensor does not crash
 PASS LinearAccelerationSensor: sensor is suspended and resumed when focus traverses from to cross-origin frame
 PASS LinearAccelerationSensor: sensor is not suspended when focus traverses from to same-origin frame
+PASS LinearAccelerationSensor: losing a document's frame with an active sensor does not crash
 FAIL GravitySensor: sensor is suspended and resumed when focus traverses from to cross-origin frame assert_true: expected true got false
 FAIL GravitySensor: sensor is not suspended when focus traverses from to same-origin frame assert_true: expected true got false
+FAIL GravitySensor: losing a document's frame with an active sensor does not crash assert_true: expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg
index 48737c0..3fabeb01 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-masking/mask-svg-content/reference/mask-text-001-ref.svg
@@ -1,8 +1,9 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:html="http://www.w3.org/1999/xhtml"
+     width="100px" height="100px">
 <g id="testmeta">
 	<title>CSS Masking: Reftest reference</title>
 	<html:link rel="author" title="Dirk Schulze" href="mailto:dschulze@adobe.com"/>
 	<metadata class="flags">svg</metadata>
 </g>
 <text fill="#000" font-family="Ahem" font-size="12px" transform="rotate(90 50 50)" x="50" y="50">foobar</text>
-</svg>
\ No newline at end of file
+</svg>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/generic-sensor-iframe-tests.sub.js b/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/generic-sensor-iframe-tests.sub.js
index 97defcb..c4195fee 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/generic-sensor-iframe-tests.sub.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/generic-sensor/generic-sensor-iframe-tests.sub.js
@@ -5,7 +5,6 @@
 
   return new Promise((resolve, reject) => {
     let messageHandler = e => {
-
       if (e.data.command !== message.command) {
         return;
       }
@@ -131,4 +130,31 @@
     iframe.parentNode.removeChild(iframe);
   }, `${sensorName}: sensor is not suspended when focus traverses from\
  to same-origin frame`);
+
+  sensor_test(async t => {
+    assert_true(sensorName in self);
+    const iframe = document.createElement('iframe');
+    iframe.allow = featurePolicies.join(';') + ';';
+    iframe.src = 'https://{{host}}:{{ports[https][0]}}/generic-sensor/resources/iframe_sensor_handler.html';
+
+    // Create sensor in the iframe (we do not care whether this is a
+    // cross-origin nested context in this test).
+    const iframeLoadWatcher = new EventWatcher(t, iframe, 'load');
+    document.body.appendChild(iframe);
+    await iframeLoadWatcher.wait_for('load');
+    await send_message_to_iframe(iframe, {command: 'create_sensor',
+                                          type: sensorName});
+    iframe.contentWindow.focus();
+    await send_message_to_iframe(iframe, {command: 'start_sensor'});
+
+    // Remove iframe from main document and change focus. When focus changes,
+    // we need to determine whether a sensor must have its execution suspended
+    // or resumed (section 4.2.3, "Focused Area" of the Generic Sensor API
+    // spec). In Blink, this involves querying a frame, which might no longer
+    // exist at the time of the check.
+    // Note that we cannot send the "reset_sensor_backend" command because the
+    // iframe is discarded with the removeChild call.
+    iframe.parentNode.removeChild(iframe);
+    window.focus();
+  }, `${sensorName}: losing a document's frame with an active sensor does not crash`);
 }
diff --git a/third_party/WebKit/LayoutTests/external/wpt/geolocation-sensor/GeolocationSensor-iframe-access.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/geolocation-sensor/GeolocationSensor-iframe-access.https-expected.txt
index 2c7055c99..4edc290 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/geolocation-sensor/GeolocationSensor-iframe-access.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/geolocation-sensor/GeolocationSensor-iframe-access.https-expected.txt
@@ -1,5 +1,6 @@
 This is a testharness.js-based test.
 FAIL GeolocationSensor: sensor is suspended and resumed when focus traverses from to cross-origin frame assert_true: expected true got false
 FAIL GeolocationSensor: sensor is not suspended when focus traverses from to same-origin frame assert_true: expected true got false
+FAIL GeolocationSensor: losing a document's frame with an active sensor does not crash assert_true: expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/magnetometer/Magnetometer-iframe-access.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/magnetometer/Magnetometer-iframe-access.https-expected.txt
index f3af520..6311057 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/magnetometer/Magnetometer-iframe-access.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/magnetometer/Magnetometer-iframe-access.https-expected.txt
@@ -1,7 +1,9 @@
 This is a testharness.js-based test.
 PASS Magnetometer: sensor is suspended and resumed when focus traverses from to cross-origin frame
 PASS Magnetometer: sensor is not suspended when focus traverses from to same-origin frame
+PASS Magnetometer: losing a document's frame with an active sensor does not crash
 FAIL UncalibratedMagnetometer: sensor is suspended and resumed when focus traverses from to cross-origin frame assert_true: expected true got false
 FAIL UncalibratedMagnetometer: sensor is not suspended when focus traverses from to same-origin frame assert_true: expected true got false
+FAIL UncalibratedMagnetometer: losing a document's frame with an active sensor does not crash assert_true: expected true got false
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webxr/resources/webxr_util.js b/third_party/WebKit/LayoutTests/external/wpt/webxr/resources/webxr_util.js
index d73cf8d..5437513 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webxr/resources/webxr_util.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/webxr/resources/webxr_util.js
@@ -112,7 +112,6 @@
   callback(window.XRCoordinateSystem, 'XRCoordinateSystem');
   callback(window.XRFrameOfReference, 'XRFrameOfReference');
   callback(window.XRStageBounds, 'XRStageBounds');
-  callback(window.XRStageBoundsPoint, 'XRStageBoundsPoint');
   callback(window.XRSessionEvent, 'XRSessionEvent');
   callback(window.XRCoordinateSystemEvent, 'XRCoordinateSystemEvent');
 }
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/select-in-shadowdom-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/shadow/select-in-shadowdom-expected.txt
index f273406..034bd29 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/select-in-shadowdom-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/select-in-shadowdom-expected.txt
@@ -2,7 +2,7 @@
 When selecting from non-anchor Node to anchor node in ShadowDOM, client should not cause page jump.
 
 Selecting from a node to another node in ShadowDOM. This should not start page navigation.
-PASS lastClickTarget is host
+PASS lastClickTarget is null
 
 Clicking a node in ShadowDOM.
 PASS lastClickTarget is host
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/select-in-shadowdom.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/select-in-shadowdom.html
index 18d16077..b0d74706 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/select-in-shadowdom.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/select-in-shadowdom.html
@@ -31,7 +31,7 @@
 eventSender.mouseDown();
 mouseMoveTo(shadowRoot.firstChild.nextSibling);
 eventSender.mouseUp();
-shouldBe('lastClickTarget', 'host');
+shouldBeNull('lastClickTarget');
 debug('');
 
 lastClickTarget = null;
diff --git a/third_party/WebKit/LayoutTests/fast/events/click-over-descendant-elements-expected.txt b/third_party/WebKit/LayoutTests/fast/events/click-over-descendant-elements-expected.txt
index 023c942..b4f3fcd6 100644
--- a/third_party/WebKit/LayoutTests/fast/events/click-over-descendant-elements-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/events/click-over-descendant-elements-expected.txt
@@ -23,7 +23,7 @@
 Click on disappearing INPUT value:
 PASS lastClickTarget is input1
 Mousedown on a form control, and mouseup on an element outside:
-PASS lastClickTarget is document.body
+PASS lastClickTarget is null
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/events/click-over-descendant-elements.html b/third_party/WebKit/LayoutTests/fast/events/click-over-descendant-elements.html
index 3219044..ac92106 100644
--- a/third_party/WebKit/LayoutTests/fast/events/click-over-descendant-elements.html
+++ b/third_party/WebKit/LayoutTests/fast/events/click-over-descendant-elements.html
@@ -131,7 +131,7 @@
 eventSender.mouseDown();
 eventSender.mouseMoveTo((spanRect.left + spanRect.right) / 2, spanRect.top + 1);
 eventSender.mouseUp();
-shouldBe('lastClickTarget', 'document.body');
+shouldBeNull('lastClickTarget');
 lastClickTarget = null;
 
 container.remove();
diff --git a/third_party/WebKit/LayoutTests/http/tests/background_fetch/fetch.https.html b/third_party/WebKit/LayoutTests/http/tests/background_fetch/fetch.https.html
new file mode 100644
index 0000000..50dfd3d5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/background_fetch/fetch.https.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Background Fetch API: CORS preflight blocking test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/serviceworker/resources/test-helpers.js"></script>
+<script src="resources/utils.js"></script>
+<script>
+'use strict';
+
+// https://crbug.com/889401
+backgroundFetchTest(async (t, bgFetch) => {
+  const registrationPromises = [];
+  for (let i = 0; i < 6; i++) {
+    const registrationPromise = bgFetch.fetch(
+        `my-fetch-${i}`,
+        '/serviceworker/resources/slow-response.php');
+    registrationPromises.push(registrationPromise);
+  }
+
+  try {
+    await Promise.all(registrationPromises);
+    assert_unreached('Should have rejected the registration exceeding the limit');
+  } catch (e) {
+    assert_equals(e.message, 'There are too many active fetches for this origin.');
+  }
+
+}, 'Registration rejected after limit exceeded');
+
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger/live-edit-no-reveal-expected.txt b/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger/live-edit-no-reveal-expected.txt
index b05f78a..9e97d9e 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger/live-edit-no-reveal-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger/live-edit-no-reveal-expected.txt
@@ -1,24 +1,6 @@
 Tests live edit feature.
 
 
-Running: testLiveEditWithoutStepInWhenPausedDoesNotCauseCursorMove
-Script execution paused.
-Moving cursor to (0, 0).
-Committing live edit.
-Script execution paused.
-Script execution resumed.
-Cursor position is: (0, 0).
-
-Running: testLiveEditWithStepInWhenPausedDoesNotCauseCursorMove
-Script execution paused.
-Moving cursor to (0, 0).
-Committing live edit.
-Did step into
-Script execution resumed.
-Script execution paused.
-Script execution resumed.
-Cursor position is: (0, 0).
-
 Running: testLiveEditWithoutStepInWhenPausedThenStepIntoCausesCursorMove
 Script execution paused.
 Moving cursor to (0, 0).
@@ -45,3 +27,21 @@
 Script execution resumed.
 Cursor position is: (8, 4).
 
+Running: testLiveEditWithoutStepInWhenPausedDoesNotCauseCursorMove
+Script execution paused.
+Moving cursor to (0, 0).
+Committing live edit.
+Script execution paused.
+Script execution resumed.
+Cursor position is: (0, 0).
+
+Running: testLiveEditWithStepInWhenPausedDoesNotCauseCursorMove
+Script execution paused.
+Moving cursor to (0, 0).
+Committing live edit.
+Did step into
+Script execution resumed.
+Script execution paused.
+Script execution resumed.
+Cursor position is: (0, 0).
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js b/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js
index ab9e84b7..05892fd6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js
+++ b/third_party/WebKit/LayoutTests/http/tests/devtools/sources/debugger/live-edit-no-reveal.js
@@ -64,7 +64,7 @@
       sourceFrame = panel.visibleView;
       SourcesTestRunner.removeBreakpoint(sourceFrame, 8);
       TestRunner.addSniffer(TestRunner.debuggerModel, '_didEditScriptSource', didEditScriptSource);
-      panel._updateLastModificationTimeForTest();
+      panel._lastModificationTimeoutPassedForTest();
       SourcesTestRunner.replaceInSource(sourceFrame, oldText, newText);
       TestRunner.addResult('Moving cursor to (0, 0).');
       sourceFrame.setSelection(TextUtils.TextRange.createFromLocation(0, 0));
@@ -92,20 +92,20 @@
   }
 
   SourcesTestRunner.runDebuggerTestSuite([
-    function testLiveEditWithoutStepInWhenPausedDoesNotCauseCursorMove(next) {
-      testLiveEditWhenPausedDoesNotCauseCursorMove('function f2()', ' function f2()', next);
-    },
-
-    function testLiveEditWithStepInWhenPausedDoesNotCauseCursorMove(next) {
-      testLiveEditWhenPausedDoesNotCauseCursorMove('return x + f2();', 'return x + f2(); ', next);
-    },
-
     function testLiveEditWithoutStepInWhenPausedThenStepIntoCausesCursorMove(next) {
       testLiveEditWhenPausedThenStepIntoCausesCursorMove('function f2()', ' function f2()', next);
     },
 
     function testLiveEditWithStepInWhenPausedThenStepIntoCausesCursorMove(next) {
       testLiveEditWhenPausedThenStepIntoCausesCursorMove('return x + f2();', 'return x + f2(); ', next);
+    },
+
+    function testLiveEditWithoutStepInWhenPausedDoesNotCauseCursorMove(next) {
+      testLiveEditWhenPausedDoesNotCauseCursorMove('function f2()', ' function f2()', next);
+    },
+
+    function testLiveEditWithStepInWhenPausedDoesNotCauseCursorMove(next) {
+      testLiveEditWhenPausedDoesNotCauseCursorMove('return x + f2();', 'return x + f2(); ', next);
     }
   ]);
 })();
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
index 7d03361d..90cc799 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-transceivers.https-expected.txt
@@ -23,7 +23,7 @@
 PASS addTransceiver(track): creates a transceiver for the track
 PASS addTransceiver(track): "transceiver == {sender,receiver}"
 PASS addTransceiver(track, init): initialize direction to inactive
-FAIL addTransceiver(track, init): initialize sendEncodings[0].active to false assert_false: expected false got true
+PASS addTransceiver(track, init): initialize sendEncodings[0].active to false
 PASS addTransceiver(0 streams): ontrack fires with no stream
 PASS addTransceiver(1 stream): ontrack fires with corresponding stream
 PASS addTransceiver(2 streams): ontrack fires with corresponding two streams
diff --git a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt
index b10eaf6..b09ee3d2 100644
--- a/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCRtpParameters-encodings-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 PASS addTransceiver() with undefined sendEncodings should have default encoding parameter with active set to true
 PASS addTransceiver() with empty list sendEncodings should have default encoding parameter with active set to true
-FAIL sender.getParameters() should return sendEncodings set by addTransceiver() assert_equals: expected (string) "enabled" but got (undefined) undefined
+FAIL sender.getParameters() should return sendEncodings set by addTransceiver() promise_test: Unhandled rejection with value: object "InvalidAccessError: Failed to execute 'setRemoteDescription' on 'RTCPeerConnection': Failed to set remote answer sdp: Failed to set remote audio description send parameters."
 PASS sender.setParameters() with mismatch number of encodings should reject with InvalidModificationError
 FAIL sender.setParameters() with encodings unset should reject with InvalidModificationError assert_throws: function "function() { throw e }" threw object "TypeError: Failed to execute 'setParameters' on 'RTCRtpSender': required member encodings is undefined." that is not a DOMException InvalidModificationError: property "code" is equal to undefined, expected 13
 FAIL setParameters() with modified encoding.rtx field should reject with InvalidModificationError assert_unreached: Should have rejected: undefined Reached unreachable code
@@ -12,13 +12,13 @@
 FAIL setParameters() with modified encoding.dtx should succeed without RTCRtpTransceiverInit assert_equals: expected (string) "enabled" but got (undefined) undefined
 FAIL setParameters() with unset encoding.dtx should succeed with RTCRtpTransceiverInit assert_equals: expected (string) "enabled" but got (undefined) undefined
 FAIL setParameters() with unset encoding.dtx should succeed without RTCRtpTransceiverInit assert_equals: expected (string) "enabled" but got (undefined) undefined
-FAIL setParameters() with modified encoding.active should succeed with RTCRtpTransceiverInit assert_equals: expected false but got true
+PASS setParameters() with modified encoding.active should succeed with RTCRtpTransceiverInit
 PASS setParameters() with modified encoding.active should succeed without RTCRtpTransceiverInit
-FAIL setParameters() with modified encoding.priority should succeed with RTCRtpTransceiverInit assert_equals: expected "very-low" but got "low"
+PASS setParameters() with modified encoding.priority should succeed with RTCRtpTransceiverInit
 PASS setParameters() with modified encoding.priority should succeed without RTCRtpTransceiverInit
 FAIL setParameters() with modified encoding.ptime should succeed with RTCRtpTransceiverInit assert_equals: expected (number) 2 but got (undefined) undefined
 FAIL setParameters() with modified encoding.ptime should succeed without RTCRtpTransceiverInit assert_equals: expected (number) 2 but got (undefined) undefined
-FAIL setParameters() with modified encoding.maxBitrate should succeed with RTCRtpTransceiverInit assert_equals: expected (number) 10000 but got (undefined) undefined
+PASS setParameters() with modified encoding.maxBitrate should succeed with RTCRtpTransceiverInit
 PASS setParameters() with modified encoding.maxBitrate should succeed without RTCRtpTransceiverInit
 FAIL setParameters() with modified encoding.maxFramerate should succeed with RTCRtpTransceiverInit assert_equals: expected (number) 24 but got (undefined) undefined
 FAIL setParameters() with modified encoding.maxFramerate should succeed without RTCRtpTransceiverInit assert_equals: expected (number) 24 but got (undefined) undefined
diff --git a/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom b/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom
index 915ce7e..3e3b635 100644
--- a/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom
+++ b/third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom
@@ -19,7 +19,8 @@
   STORAGE_ERROR,
   SERVICE_WORKER_UNAVAILABLE,
   QUOTA_EXCEEDED,
-  PERMISSION_DENIED
+  PERMISSION_DENIED,
+  REGISTRATION_LIMIT_EXCEEDED
 };
 
 // Struct representing completed Background Fetch requests, along with their
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
index b60cc8c..2e454802 100644
--- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
+++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
@@ -135,7 +135,9 @@
 These are defined in the [ECMAScript-specific extended attributes](http://heycam.github.io/webidl/#es-extended-attributes) section of the [Web IDL spec](http://heycam.github.io/webidl/), and alter the binding behavior.
 
 *** note
-Unsupported: `[ImplicitThis]`, `[LenientThis]`, `[NamedPropertiesObject]`, `[TreatNonCallableAsNull]`
+Unsupported: `[LenientThis]`
+
+Undocumented: `[TreatNonObjectAsNull]`
 ***
 
 ### [CEReactions] _(m, a)_
@@ -485,6 +487,34 @@
 }
 ```
 
+### [Serializable] _(i)_
+
+Standard: [Serializable](https://html.spec.whatwg.org/multipage/structured-data.html#serializable)
+
+Summary: Serializable objects support being serialized, and later deserialized, for persistence in storage APIs or for passing with `postMessage()`.
+
+```webidl
+[Serializable] interface Blob {
+    ...
+};
+```
+
+This attribute has no effect on code generation and should simply be used in Blink IDL files if the specification uses it. Code to perform the serialization/deserialization must be added to `V8ScriptValueSerializer` for types in `core/` or `V8ScriptValueDeserializerForModules` for types in `modules/`.
+
+### [Transferable] _(i)_
+
+Standard: [Transferable](https://html.spec.whatwg.org/multipage/structured-data.html#transferable)
+
+Summary: Transferable objects support being transferred across Realms with `postMessage()`.
+
+```webidl
+[Transferable] interface MessagePort {
+    ...
+};
+```
+
+This attribute has no effect on code generation and should simply be used in Blink IDL files if the specification uses it. Code to perform the transfer steps must be added to `V8ScriptValueSerializer` for types in `core/` or `V8ScriptValueDeserializerForModules` for types in `modules/`.
+
 ### [TreatNullAs] _(a,p)_
 
 Standard: [TreatNullAs](https://heycam.github.io/webidl/#TreatNullAs)
@@ -1633,8 +1663,12 @@
 **FIXME:** The following need documentation:
 ***
 
-* `[PerWorldBindings]` :: interacts with `[LogActivity]`
+* `[ImmutablePrototype]`
+* `[LegacyInterfaceTypeChecking]`
+* `[LogAllWorlds]`
 * `[OverrideBuiltins]` :: used on named accessors
+* `[PerWorldBindings]` :: interacts with `[LogActivity]`
+* `[WebAgentAPI]`
 
 -------------
 
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
index 090f8dae..993ca86 100644
--- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
+++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
@@ -97,7 +97,9 @@
 SameObject
 SaveSameObject
 SecureContext=|*
+Serializable
 SetterCallWith=ExecutionContext|ScriptState|ScriptArguments|CurrentWindow|EnteredWindow
+Transferable
 TreatNonObjectAsNull
 TreatNullAs=NullString|EmptyString
 URL
diff --git a/third_party/blink/renderer/core/fileapi/blob.idl b/third_party/blink/renderer/core/fileapi/blob.idl
index fa0d250..27393e6 100644
--- a/third_party/blink/renderer/core/fileapi/blob.idl
+++ b/third_party/blink/renderer/core/fileapi/blob.idl
@@ -28,14 +28,15 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// https://w3c.github.io/FileAPI/#blob
+// https://w3c.github.io/FileAPI/#blob-section
 
 typedef (ArrayBuffer or ArrayBufferView or Blob or USVString) BlobPart;
 [
     Constructor(optional sequence<BlobPart> blobParts, optional BlobPropertyBag options),
     ConstructorCallWith=ExecutionContext,
     RaisesException=Constructor,
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable
 ] interface Blob {
     readonly attribute unsigned long long size;
     readonly attribute DOMString type;
diff --git a/third_party/blink/renderer/core/fileapi/file.idl b/third_party/blink/renderer/core/fileapi/file.idl
index a74beced..940f8e6 100644
--- a/third_party/blink/renderer/core/fileapi/file.idl
+++ b/third_party/blink/renderer/core/fileapi/file.idl
@@ -23,13 +23,14 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-// https://w3c.github.io/FileAPI/#file
+// https://w3c.github.io/FileAPI/#file-section
 
 [
     Constructor(sequence<BlobPart> fileBits, USVString fileName, optional FilePropertyBag options),
     ConstructorCallWith=ExecutionContext,
     RaisesException=Constructor,
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable
 ] interface File : Blob {
     readonly attribute DOMString name;
     readonly attribute long long lastModified;
diff --git a/third_party/blink/renderer/core/fileapi/file_list.idl b/third_party/blink/renderer/core/fileapi/file_list.idl
index 25db9a0..017fd425e 100644
--- a/third_party/blink/renderer/core/fileapi/file_list.idl
+++ b/third_party/blink/renderer/core/fileapi/file_list.idl
@@ -26,7 +26,8 @@
 // https://w3c.github.io/FileAPI/#filelist-section
 
 [
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable
 ] interface FileList {
     getter File? item(unsigned long index);
     readonly attribute unsigned long length;
diff --git a/third_party/blink/renderer/core/geometry/dom_matrix.idl b/third_party/blink/renderer/core/geometry/dom_matrix.idl
index cbb7be8ac..2af00ad 100644
--- a/third_party/blink/renderer/core/geometry/dom_matrix.idl
+++ b/third_party/blink/renderer/core/geometry/dom_matrix.idl
@@ -8,7 +8,8 @@
     Constructor(optional (DOMString or sequence<unrestricted double>) init),
     RaisesException=Constructor,
     ConstructorCallWith=ExecutionContext,
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable
 ] interface DOMMatrix : DOMMatrixReadOnly {
     [RaisesException, NewObject] static DOMMatrix fromMatrix(optional DOMMatrixInit other);
     [RaisesException, NewObject] static DOMMatrix fromFloat32Array(Float32Array array32);
diff --git a/third_party/blink/renderer/core/geometry/dom_matrix_read_only.idl b/third_party/blink/renderer/core/geometry/dom_matrix_read_only.idl
index 6f392d4..803bbd11 100644
--- a/third_party/blink/renderer/core/geometry/dom_matrix_read_only.idl
+++ b/third_party/blink/renderer/core/geometry/dom_matrix_read_only.idl
@@ -8,7 +8,8 @@
     Constructor(optional (DOMString or sequence<unrestricted double>) init),
     RaisesException=Constructor,
     ConstructorCallWith=ExecutionContext,
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable
 ] interface DOMMatrixReadOnly {
     [RaisesException, NewObject] static DOMMatrixReadOnly fromMatrix(optional DOMMatrixInit other);
     [RaisesException, NewObject] static DOMMatrixReadOnly fromFloat32Array(Float32Array array32);
diff --git a/third_party/blink/renderer/core/geometry/dom_point.idl b/third_party/blink/renderer/core/geometry/dom_point.idl
index 2f416d6..a2e04a27 100644
--- a/third_party/blink/renderer/core/geometry/dom_point.idl
+++ b/third_party/blink/renderer/core/geometry/dom_point.idl
@@ -7,7 +7,8 @@
 [
     Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0,
                 optional unrestricted double z = 0, optional unrestricted double w = 1),
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable
 ] interface DOMPoint : DOMPointReadOnly {
     [NewObject] static DOMPoint fromPoint(optional DOMPointInit other);
     inherit attribute unrestricted double x;
diff --git a/third_party/blink/renderer/core/geometry/dom_point_read_only.idl b/third_party/blink/renderer/core/geometry/dom_point_read_only.idl
index f9c19010..1075a7e 100644
--- a/third_party/blink/renderer/core/geometry/dom_point_read_only.idl
+++ b/third_party/blink/renderer/core/geometry/dom_point_read_only.idl
@@ -7,7 +7,8 @@
 [
     Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0,
                 optional unrestricted double z = 0, optional unrestricted double w = 1),
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable
 ] interface DOMPointReadOnly {
     [NewObject] static DOMPointReadOnly fromPoint(optional DOMPointInit other);
 
diff --git a/third_party/blink/renderer/core/geometry/dom_quad.idl b/third_party/blink/renderer/core/geometry/dom_quad.idl
index bde705c6..0af1f80 100644
--- a/third_party/blink/renderer/core/geometry/dom_quad.idl
+++ b/third_party/blink/renderer/core/geometry/dom_quad.idl
@@ -7,7 +7,8 @@
 [
  Constructor(optional DOMPointInit p1, optional DOMPointInit p2,
                   optional DOMPointInit p3, optional DOMPointInit p4),
- Exposed=(Window,Worker)
+ Exposed=(Window,Worker),
+ Serializable
 ]
 interface DOMQuad {
     [NewObject] static DOMQuad fromRect(optional DOMRectInit other);
diff --git a/third_party/blink/renderer/core/geometry/dom_rect.idl b/third_party/blink/renderer/core/geometry/dom_rect.idl
index 72ad05b..45171c08 100644
--- a/third_party/blink/renderer/core/geometry/dom_rect.idl
+++ b/third_party/blink/renderer/core/geometry/dom_rect.idl
@@ -9,7 +9,8 @@
                 optional unrestricted double y = 0,
                 optional unrestricted double width = 0,
                 optional unrestricted double height = 0),
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable
 ] interface DOMRect : DOMRectReadOnly {
     [NewObject] static DOMRect fromRect(optional DOMRectInit other);
 
diff --git a/third_party/blink/renderer/core/geometry/dom_rect_read_only.idl b/third_party/blink/renderer/core/geometry/dom_rect_read_only.idl
index e64c077c..9cd5961 100644
--- a/third_party/blink/renderer/core/geometry/dom_rect_read_only.idl
+++ b/third_party/blink/renderer/core/geometry/dom_rect_read_only.idl
@@ -7,7 +7,8 @@
 [
     Constructor(optional unrestricted double x = 0, optional unrestricted double y = 0,
                 optional unrestricted double width = 0, optional unrestricted double height = 0),
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable
 ] interface DOMRectReadOnly {
     [NewObject] static DOMRectReadOnly fromRect(optional DOMRectInit other);
 
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 58560f2..b378855 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -487,7 +487,7 @@
       FloatRect mapped_dirty_rect =
           MapRect(dirty_rect_, src_rect, content_rect);
       if (context_->IsComposited()) {
-        // Accelerated 2D canvases need the dirty rect to be expressed relative
+        // Composited 2D canvases need the dirty rect to be expressed relative
         // to the content box, as opposed to the layout box.
         mapped_dirty_rect.MoveBy(-content_rect.Location());
       }
@@ -1110,13 +1110,15 @@
   return canvas2d_bridge_.get();
 }
 
-void HTMLCanvasElement::SetCanvas2DLayerBridgeForTesting(
+void HTMLCanvasElement::SetResourceProviderForTesting(
+    std::unique_ptr<CanvasResourceProvider> resource_provider,
     std::unique_ptr<Canvas2DLayerBridge> bridge,
     const IntSize& size) {
   DiscardResourceProvider();
   SetIntegralAttribute(widthAttr, size.Width());
   SetIntegralAttribute(heightAttr, size.Height());
   SetCanvas2DLayerBridgeInternal(std::move(bridge));
+  ReplaceResourceProvider(std::move(resource_provider));
 }
 
 void HTMLCanvasElement::DiscardResourceProvider() {
@@ -1393,9 +1395,12 @@
 void HTMLCanvasElement::UpdateMemoryUsage() {
   int non_gpu_buffer_count = 0;
   int gpu_buffer_count = 0;
-  if (Is2d() && canvas2d_bridge_) {
+
+  if (!Is2d() && !Is3d())
+    return;
+  if (ResourceProvider()) {
     non_gpu_buffer_count++;
-    if (canvas2d_bridge_->IsAccelerated()) {
+    if (IsAccelerated()) {
       // The number of internal GPU buffers vary between one (stable
       // non-displayed state) and three (triple-buffered animations).
       // Adding 2 is a pessimistic but relevant estimate.
@@ -1404,14 +1409,8 @@
     }
   }
 
-  if (Is3d()) {
-    if (ResourceProvider()) {
-      non_gpu_buffer_count++;
-      if (ResourceProvider()->IsAccelerated())
-        gpu_buffer_count += 2;
-    }
+  if (Is3d())
     non_gpu_buffer_count += context_->ExternallyAllocatedBufferCountPerPixel();
-  }
 
   const int bytes_per_pixel = ColorParams().BytesPerPixel();
 
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
index 064d390..9bd1a6d3 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -234,8 +234,9 @@
                            unsigned resource_id) override;
   void Trace(blink::Visitor*) override;
 
-  void SetCanvas2DLayerBridgeForTesting(std::unique_ptr<Canvas2DLayerBridge>,
-                                        const IntSize&);
+  void SetResourceProviderForTesting(std::unique_ptr<CanvasResourceProvider>,
+                                     std::unique_ptr<Canvas2DLayerBridge>,
+                                     const IntSize&);
 
   static void RegisterRenderingContextFactory(
       std::unique_ptr<CanvasRenderingContextFactory>);
diff --git a/third_party/blink/renderer/core/html/canvas/image_data.idl b/third_party/blink/renderer/core/html/canvas/image_data.idl
index ef22e2e..03bf6e3 100644
--- a/third_party/blink/renderer/core/html/canvas/image_data.idl
+++ b/third_party/blink/renderer/core/html/canvas/image_data.idl
@@ -27,7 +27,7 @@
  */
 
 // https://html.spec.whatwg.org/#dom-imagedata
-// https://github.com/junov/CanvasColorSpace/blob/master/CanvasColorSpaceProposal.md#imagedata
+// https://github.com/WICG/canvas-color-space/blob/master/CanvasColorSpaceProposal.md#imagedata
 
 typedef (Uint8ClampedArray or Uint16Array or Float32Array) ImageDataArray;
 
@@ -35,7 +35,8 @@
     Constructor(unsigned long sw, unsigned long sh),
     Constructor(Uint8ClampedArray data, unsigned long sw, optional unsigned long sh),
     Exposed=(Window,Worker),
-    RaisesException=Constructor
+    RaisesException=Constructor,
+    Serializable
 ] interface ImageData {
     [RuntimeEnabled=CanvasColorManagement] ImageDataColorSettings getColorSettings();
 
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.idl b/third_party/blink/renderer/core/imagebitmap/image_bitmap.idl
index 8e0df94..c27b0b3b9 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.idl
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.idl
@@ -2,10 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://html.spec.whatwg.org/#images
+// https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#images-2
 
 [
-    Exposed=(Window,Worker)
+    Exposed=(Window,Worker),
+    Serializable,
+    Transferable
 ] interface ImageBitmap {
     readonly attribute unsigned long width;
     readonly attribute unsigned long height;
diff --git a/third_party/blink/renderer/core/input/event_handling_util.cc b/third_party/blink/renderer/core/input/event_handling_util.cc
index 94722e19..6404452c 100644
--- a/third_party/blink/renderer/core/input/event_handling_util.cc
+++ b/third_party/blink/renderer/core/input/event_handling_util.cc
@@ -100,6 +100,11 @@
 }
 
 ContainerNode* ParentForClickEvent(const Node& node) {
+  // IE doesn't dispatch click events for mousedown/mouseup events across form
+  // controls.
+  if (node.IsHTMLElement() && ToHTMLElement(node).IsInteractiveContent())
+    return nullptr;
+
   return FlatTreeTraversal::Parent(node);
 }
 
diff --git a/third_party/blink/renderer/core/input/mouse_event_manager.cc b/third_party/blink/renderer/core/input/mouse_event_manager.cc
index 7f030d4..953ba5f 100644
--- a/third_party/blink/renderer/core/input/mouse_event_manager.cc
+++ b/third_party/blink/renderer/core/input/mouse_event_manager.cc
@@ -915,14 +915,15 @@
     return true;
   }
 
+  // Once we're past the drag threshold, we don't want to treat this gesture as
+  // a click.
+  InvalidateClick();
+
   if (!TryStartDrag(event)) {
     // Something failed to start the drag, clean up.
     ClearDragDataTransfer();
     ResetDragState();
   } else {
-    // Once the drag operation is initiated, we don't want to treat this
-    // gesture as a click.
-    InvalidateClick();
     // Since drag operation started we need to send a pointercancel for the
     // corresponding pointer.
     if (initiator == DragInitiator::kMouse) {
diff --git a/third_party/blink/renderer/core/messaging/message_port.idl b/third_party/blink/renderer/core/messaging/message_port.idl
index 60163f1..78e26bf7 100644
--- a/third_party/blink/renderer/core/messaging/message_port.idl
+++ b/third_party/blink/renderer/core/messaging/message_port.idl
@@ -25,11 +25,12 @@
  *
  */
 
-// https://html.spec.whatwg.org/#message-ports
+// https://html.spec.whatwg.org/multipage/web-messaging.html#message-ports
 
 [
     ActiveScriptWrappable,
-    Exposed=(Window,Worker,AudioWorklet)
+    Exposed=(Window,Worker,AudioWorklet),
+    Transferable
 ] interface MessagePort : EventTarget {
     [CallWith=ScriptState, RaisesException, Measure] void postMessage(any message, optional sequence<object> transfer = []);
     [RuntimeEnabled=PostMessageOptions, CallWith=ScriptState, RaisesException, Measure] void postMessage(any message, PostMessageOptions options);
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl
index 1949f93..e939cf9 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl
@@ -7,6 +7,7 @@
 [
     Constructor([EnforceRange] unsigned long width, [EnforceRange] unsigned long height),
     Exposed=(Window,Worker),
+    Transferable,
     RuntimeEnabled=OffscreenCanvas,
     MeasureAs=OffscreenCanvas
 ] interface OffscreenCanvas : EventTarget {
diff --git a/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc b/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
index d0c7c1d..5f9839a 100644
--- a/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
+++ b/third_party/blink/renderer/core/paint/html_canvas_painter_test.cc
@@ -91,7 +91,7 @@
       element->GetCanvasRenderingContext("2d", attributes);
   IntSize size(300, 200);
   std::unique_ptr<Canvas2DLayerBridge> bridge = MakeCanvas2DLayerBridge(size);
-  element->SetCanvas2DLayerBridgeForTesting(std::move(bridge), size);
+  element->SetResourceProviderForTesting(nullptr, std::move(bridge), size);
   ASSERT_EQ(context, element->RenderingContext());
   ASSERT_TRUE(context->IsComposited());
   ASSERT_TRUE(element->IsAccelerated());
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
index 500e8a6..515a067 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -342,6 +342,11 @@
       resolver->Reject(DOMException::Create(
           DOMExceptionCode::kQuotaExceededError, "Quota exceeded."));
       return;
+    case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED:
+      resolver->Reject(V8ThrowException::CreateTypeError(
+          script_state->GetIsolate(),
+          "There are too many active fetches for this origin."));
+      return;
     case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT:
     case mojom::blink::BackgroundFetchError::INVALID_ID:
       // Not applicable for this callback.
@@ -477,6 +482,7 @@
     case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT:
     case mojom::blink::BackgroundFetchError::PERMISSION_DENIED:
     case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED:
+    case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED:
       // Not applicable for this callback.
       break;
   }
@@ -528,6 +534,7 @@
     case mojom::blink::BackgroundFetchError::PERMISSION_DENIED:
     case mojom::blink::BackgroundFetchError::SERVICE_WORKER_UNAVAILABLE:
     case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED:
+    case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED:
       // Not applicable for this callback.
       break;
   }
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
index 86d0135..819479c 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_registration.cc
@@ -275,6 +275,7 @@
     case mojom::blink::BackgroundFetchError::INVALID_ARGUMENT:
     case mojom::blink::BackgroundFetchError::PERMISSION_DENIED:
     case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED:
+    case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED:
       // Not applicable for this callback.
       break;
   }
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc
index 04425ed..824f86a 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_update_ui_event.cc
@@ -117,6 +117,7 @@
     case mojom::blink::BackgroundFetchError::SERVICE_WORKER_UNAVAILABLE:
     case mojom::blink::BackgroundFetchError::PERMISSION_DENIED:
     case mojom::blink::BackgroundFetchError::QUOTA_EXCEEDED:
+    case mojom::blink::BackgroundFetchError::REGISTRATION_LIMIT_EXCEEDED:
       // Not applicable for this callback.
       break;
   }
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
index e9e23221..9a83b5c 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_test.cc
@@ -276,6 +276,30 @@
 
 //============================================================================
 
+class FakeCanvasResourceProvider : public CanvasResourceProvider {
+ public:
+  FakeCanvasResourceProvider(const IntSize& size,
+                             CanvasColorParams color_params,
+                             AccelerationHint hint)
+      : CanvasResourceProvider(size, color_params, nullptr, nullptr),
+        is_accelerated_(hint != kPreferNoAcceleration) {}
+  ~FakeCanvasResourceProvider() override = default;
+  bool IsAccelerated() const override { return is_accelerated_; }
+  scoped_refptr<CanvasResource> ProduceFrame() override {
+    return scoped_refptr<CanvasResource>();
+  }
+  bool SupportsDirectCompositing() const override { return false; }
+  bool IsValid() const override { return false; }
+  sk_sp<SkSurface> CreateSkSurface() const override {
+    return sk_sp<SkSurface>();
+  }
+
+ private:
+  bool is_accelerated_;
+};
+
+//============================================================================
+
 class MockImageBufferSurfaceForOverwriteTesting : public Canvas2DLayerBridge {
  public:
   MockImageBufferSurfaceForOverwriteTesting(const IntSize& size,
@@ -295,8 +319,8 @@
       std::make_unique<MockImageBufferSurfaceForOverwriteTesting>(             \
           size, CanvasColorParams());                                          \
   MockImageBufferSurfaceForOverwriteTesting* surface_ptr = mock_surface.get(); \
-  CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(mock_surface),    \
-                                                   size);                      \
+  CanvasElement().SetResourceProviderForTesting(                               \
+      nullptr, std::move(mock_surface), size);                                 \
   EXPECT_CALL(*surface_ptr, WillOverwriteCanvas()).Times(EXPECTED_OVERDRAWS);  \
   Context2d()->save();
 
@@ -544,13 +568,17 @@
   CreateContext(kNonOpaque);
 
   IntSize size(10, 10);
-  std::unique_ptr<FakeCanvas2DLayerBridge> fake_accelerate_surface =
+  std::unique_ptr<FakeCanvasResourceProvider> fake_resource_provider =
+      std::make_unique<FakeCanvasResourceProvider>(size, CanvasColorParams(),
+                                                   kPreferAcceleration);
+  std::unique_ptr<FakeCanvas2DLayerBridge> fake_2d_layer_bridge =
       std::make_unique<FakeCanvas2DLayerBridge>(size, CanvasColorParams(),
                                                 kPreferAcceleration);
-  FakeCanvas2DLayerBridge* fake_accelerate_surface_ptr =
-      fake_accelerate_surface.get();
-  CanvasElement().SetCanvas2DLayerBridgeForTesting(
-      std::move(fake_accelerate_surface), size);
+  FakeCanvas2DLayerBridge* fake_2d_layer_bridge_ptr =
+      fake_2d_layer_bridge.get();
+  CanvasElement().SetResourceProviderForTesting(
+      std::move(fake_resource_provider), std::move(fake_2d_layer_bridge), size);
+
   // 800 = 10 * 10 * 4 * 2 where 10*10 is canvas size, 4 is num of bytes per
   // pixel per buffer, and 2 is an estimate of num of gpu buffers required
   EXPECT_EQ(800, GetCurrentGPUMemoryUsage());
@@ -558,14 +586,14 @@
   EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
 
   // Switching accelerated mode to non-accelerated mode
-  fake_accelerate_surface_ptr->SetIsAccelerated(false);
+  fake_2d_layer_bridge_ptr->SetIsAccelerated(false);
   CanvasElement().UpdateMemoryUsage();
   EXPECT_EQ(0, GetCurrentGPUMemoryUsage());
   EXPECT_EQ(0, GetGlobalGPUMemoryUsage());
   EXPECT_EQ(0u, GetGlobalAcceleratedContextCount());
 
   // Switching non-accelerated mode to accelerated mode
-  fake_accelerate_surface_ptr->SetIsAccelerated(true);
+  fake_2d_layer_bridge_ptr->SetIsAccelerated(true);
   CanvasElement().UpdateMemoryUsage();
   EXPECT_EQ(800, GetCurrentGPUMemoryUsage());
   EXPECT_EQ(800, GetGlobalGPUMemoryUsage());
@@ -577,17 +605,22 @@
   CanvasContextCreationAttributesCore attributes;
   anotherCanvas->GetCanvasRenderingContext("2d", attributes);
   IntSize size2(10, 5);
-  auto fake_accelerate_surface2 = std::make_unique<FakeCanvas2DLayerBridge>(
-      size2, CanvasColorParams(), kPreferAcceleration);
-  anotherCanvas->SetCanvas2DLayerBridgeForTesting(
-      std::move(fake_accelerate_surface2), size2);
+  std::unique_ptr<FakeCanvas2DLayerBridge> fake_2d_layer_bridge2 =
+      std::make_unique<FakeCanvas2DLayerBridge>(size2, CanvasColorParams(),
+                                                kPreferAcceleration);
+  std::unique_ptr<FakeCanvasResourceProvider> fake_resource_provider2 =
+      std::make_unique<FakeCanvasResourceProvider>(size2, CanvasColorParams(),
+                                                   kPreferAcceleration);
+  anotherCanvas->SetResourceProviderForTesting(
+      std::move(fake_resource_provider2), std::move(fake_2d_layer_bridge2),
+      size2);
   EXPECT_EQ(800, GetCurrentGPUMemoryUsage());
   EXPECT_EQ(1200, GetGlobalGPUMemoryUsage());
   EXPECT_EQ(2u, GetGlobalAcceleratedContextCount());
 
   // Tear down the first image buffer that resides in current canvas element
   CanvasElement().SetSize(IntSize(20, 20));
-  Mock::VerifyAndClearExpectations(fake_accelerate_surface_ptr);
+  Mock::VerifyAndClearExpectations(fake_2d_layer_bridge_ptr);
   EXPECT_EQ(400, GetGlobalGPUMemoryUsage());
   EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
 
@@ -632,7 +665,8 @@
   IntSize size(300, 300);
   std::unique_ptr<Canvas2DLayerBridge> bridge =
       MakeBridge(size, Canvas2DLayerBridge::kForceAccelerationForTesting);
-  CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(bridge), size);
+  CanvasElement().SetResourceProviderForTesting(nullptr, std::move(bridge),
+                                                size);
   DrawSomething();  // Lock-in gpu acceleration
   EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated());
   EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
@@ -666,63 +700,6 @@
   }
 }
 
-TEST_F(CanvasRenderingContext2DTest, TextureUploadHeuristics) {
-  ScopedCanvas2dFixedRenderingModeForTest canvas_2d_fixed_rendering_mode(false);
-
-  enum TestVariants {
-    kLargeTextureDisablesAcceleration = 0,
-    kSmallTextureDoesNotDisableAcceleration = 1,
-
-    kTestVariantCount = 2,
-  };
-
-  for (int test_variant = 0; test_variant < kTestVariantCount; test_variant++) {
-    int delta = test_variant == kLargeTextureDisablesAcceleration ? 1 : -1;
-    int src_size =
-        std::sqrt(static_cast<float>(
-            CanvasHeuristicParameters::kDrawImageTextureUploadSoftSizeLimit)) +
-        delta;
-    int dst_size =
-        src_size /
-            std::sqrt(static_cast<float>(
-                CanvasHeuristicParameters::
-                    kDrawImageTextureUploadSoftSizeLimitScaleThreshold)) -
-        delta;
-
-    CreateContext(kNonOpaque);
-    IntSize size(dst_size, dst_size);
-    std::unique_ptr<Canvas2DLayerBridge> bridge =
-        MakeBridge(size, Canvas2DLayerBridge::kEnableAcceleration);
-    CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(bridge), size);
-
-    EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated());
-    EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
-    // 4 bytes per pixel * 2 buffers = 8
-    EXPECT_EQ(8 * dst_size * dst_size, GetGlobalGPUMemoryUsage());
-    sk_sp<SkSurface> sk_surface =
-        SkSurface::MakeRasterN32Premul(src_size, src_size);
-    scoped_refptr<StaticBitmapImage> big_bitmap =
-        StaticBitmapImage::Create(sk_surface->makeImageSnapshot());
-    ASSERT_TRUE(big_bitmap);
-    ImageBitmap* big_image = ImageBitmap::Create(std::move(big_bitmap));
-    NonThrowableExceptionState exception_state;
-    V8TestingScope scope;
-    Context2d()->drawImage(scope.GetScriptState(), big_image, 0, 0, src_size,
-                           src_size, 0, 0, dst_size, dst_size, exception_state);
-    EXPECT_FALSE(exception_state.HadException());
-
-    if (test_variant == kLargeTextureDisablesAcceleration) {
-      EXPECT_FALSE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated());
-      EXPECT_EQ(0u, GetGlobalAcceleratedContextCount());
-      EXPECT_EQ(0, GetGlobalGPUMemoryUsage());
-    } else {
-      EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated());
-      EXPECT_EQ(1u, GetGlobalAcceleratedContextCount());
-      EXPECT_EQ(8 * dst_size * dst_size, GetGlobalGPUMemoryUsage());
-    }
-  }
-}
-
 TEST_F(CanvasRenderingContext2DTest,
        NoResourceProviderInCanvas2DBufferInitialization) {
   // This test enforces that there is no eager creation of
@@ -735,21 +712,22 @@
   IntSize size(10, 10);
   auto fake_accelerate_surface = std::make_unique<FakeCanvas2DLayerBridge>(
       size, CanvasColorParams(), kPreferAcceleration);
-  CanvasElement().SetCanvas2DLayerBridgeForTesting(
-      std::move(fake_accelerate_surface), size);
+  CanvasElement().SetResourceProviderForTesting(
+      nullptr, std::move(fake_accelerate_surface), size);
 
   EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge());
   EXPECT_FALSE(CanvasElement().ResourceProvider());
 }
 
-TEST_F(CanvasRenderingContext2DTest, DisableAcceleration_UpdateGPUMemoryUsage) {
+TEST_F(CanvasRenderingContext2DTest,
+       DISABLED_DisableAcceleration_UpdateGPUMemoryUsage) {
   CreateContext(kNonOpaque);
 
   IntSize size(10, 10);
   auto fake_accelerate_surface = std::make_unique<FakeCanvas2DLayerBridge>(
       size, CanvasColorParams(), kPreferAcceleration);
-  CanvasElement().SetCanvas2DLayerBridgeForTesting(
-      std::move(fake_accelerate_surface), size);
+  CanvasElement().SetResourceProviderForTesting(
+      nullptr, std::move(fake_accelerate_surface), size);
   CanvasRenderingContext2D* context = Context2d();
 
   // 800 = 10 * 10 * 4 * 2 where 10*10 is canvas size, 4 is num of bytes per
@@ -781,8 +759,8 @@
   IntSize size(10, 10);
   auto fake_accelerate_surface = std::make_unique<FakeCanvas2DLayerBridge>(
       size, CanvasColorParams(), kPreferAcceleration);
-  CanvasElement().SetCanvas2DLayerBridgeForTesting(
-      std::move(fake_accelerate_surface), size);
+  CanvasElement().SetResourceProviderForTesting(
+      nullptr, std::move(fake_accelerate_surface), size);
 
   FakeCanvasResourceHost host(size);
   auto fake_deaccelerate_surface = std::make_unique<FakeCanvas2DLayerBridge>(
@@ -1079,7 +1057,8 @@
       MakeBridge(size, Canvas2DLayerBridge::kEnableAcceleration);
   // Force hibernatation to occur in an immediate task.
   bridge->DontUseIdleSchedulingForTesting();
-  CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(bridge), size);
+  CanvasElement().SetResourceProviderForTesting(nullptr, std::move(bridge),
+                                                size);
 
   EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated());
   // Take a snapshot to trigger lazy resource provider creation
@@ -1121,7 +1100,8 @@
       MakeBridge(size, Canvas2DLayerBridge::kEnableAcceleration);
   // Force hibernatation to occur in an immediate task.
   bridge->DontUseIdleSchedulingForTesting();
-  CanvasElement().SetCanvas2DLayerBridgeForTesting(std::move(bridge), size);
+  CanvasElement().SetResourceProviderForTesting(nullptr, std::move(bridge),
+                                                size);
 
   EXPECT_TRUE(CanvasElement().GetCanvas2DLayerBridge()->IsAccelerated());
 
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad.idl b/third_party/blink/renderer/modules/gamepad/gamepad.idl
index 4d5cc263..e4abab52 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad.idl
+++ b/third_party/blink/renderer/modules/gamepad/gamepad.idl
@@ -43,7 +43,7 @@
     // https://github.com/w3c/gamepad/pull/68
     [RuntimeEnabled=GamepadVibration, MeasureAs=GamepadVibrationActuator] readonly attribute GamepadHapticActuator? vibrationActuator;
 
-    [RuntimeEnabled=GamepadExtensions, MeasureAs=GamepadPose] readonly attribute GamepadPose? pose;
+    [OriginTrialEnabled=GamepadExtensions, MeasureAs=GamepadPose] readonly attribute GamepadPose? pose;
     [OriginTrialEnabled=WebXRGamepadSupport, MeasureAs=GamepadHand] readonly attribute GamepadHand hand;
 
     // https://w3c.github.io/webvr/#interface-gamepad
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_pose.idl b/third_party/blink/renderer/modules/gamepad/gamepad_pose.idl
index e9f87f5..05495f2 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_pose.idl
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_pose.idl
@@ -4,7 +4,7 @@
 
 // https://w3c.github.io/gamepad/extensions.html#gamepadpose-interface
 [
-    RuntimeEnabled=GamepadExtensions
+    OriginTrialEnabled=GamepadExtensions
 ] interface GamepadPose {
     [MeasureAs=GamepadPoseHasOrientation] readonly attribute boolean hasOrientation;
     [MeasureAs=GamepadPoseHasPosition] readonly attribute boolean hasPosition;
diff --git a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
index 8a939d6..51ace37 100644
--- a/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
+++ b/third_party/blink/renderer/modules/gamepad/navigator_gamepad.cc
@@ -152,7 +152,7 @@
       bool webxr_enabled =
           (context && OriginTrials::WebXRGamepadSupportEnabled(context) &&
            OriginTrials::WebXREnabled(context));
-      bool webvr_enabled = (context && RuntimeEnabledFeatures::WebVREnabled());
+      bool webvr_enabled = (context && OriginTrials::WebVREnabled(context));
 
       if (!webxr_enabled && !webvr_enabled) {
         // If neither WebXR nor WebVR are enabled, we should not expose XR-
diff --git a/third_party/blink/renderer/modules/modules_initializer.cc b/third_party/blink/renderer/modules/modules_initializer.cc
index 949e6416..ce1b704 100644
--- a/third_party/blink/renderer/modules/modules_initializer.cc
+++ b/third_party/blink/renderer/modules/modules_initializer.cc
@@ -239,7 +239,7 @@
   NavigatorGamepad::From(document);
   NavigatorServiceWorker::From(document);
   DOMWindowStorageController::From(document);
-  if (RuntimeEnabledFeatures::WebVREnabled())
+  if (OriginTrials::WebVREnabled(document.GetExecutionContext()))
     NavigatorVR::From(document);
   if (RuntimeEnabledFeatures::PresentationEnabled() &&
       settings.GetPresentationReceiver()) {
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 3ed6c7f..25b1e5f 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -1341,7 +1341,10 @@
 }
 
 void PaymentRequest::OnCanMakePayment(CanMakePaymentQueryResult result) {
-  DCHECK(can_make_payment_resolver_);
+  // TODO(https://crbug.com/891371): Understand how the resolver could be null
+  // here and prevent it.
+  if (!can_make_payment_resolver_)
+    return;
 
   switch (result) {
     case CanMakePaymentQueryResult::WARNING_CAN_MAKE_PAYMENT:
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_certificate.idl b/third_party/blink/renderer/modules/peerconnection/rtc_certificate.idl
index e80074f..44ced3e 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_certificate.idl
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_certificate.idl
@@ -29,7 +29,7 @@
  */
 
 // https://w3c.github.io/webrtc-pc/#rtccertificate-interface
-[Exposed=Window]
+[Exposed=Window, Serializable]
 interface RTCCertificate {
     // The expiration time in ms relative to epoch, 1970-01-01T00:00:00Z.
     readonly attribute DOMTimeStamp expires;
diff --git a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
index 789a24c..91e6757 100644
--- a/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
+++ b/third_party/blink/renderer/modules/peerconnection/rtc_rtp_transceiver.cc
@@ -79,9 +79,9 @@
     webrtc_init.stream_ids.push_back(stream->id().Utf8().data());
   }
   DCHECK(init.hasSendEncodings());
-  // TODO(orphis,hbos): Pass the encodings down to the lower layer using
-  // ToRtpEncodingParameters() once implemented in third_party/webrtc.
-  // https://crbug.com/803494
+  for (const auto& encoding : init.sendEncodings()) {
+    webrtc_init.send_encodings.push_back(ToRtpEncodingParameters(encoding));
+  }
   return webrtc_init;
 }
 
diff --git a/third_party/blink/renderer/modules/sensor/sensor_proxy.cc b/third_party/blink/renderer/modules/sensor/sensor_proxy.cc
index f652807..ec5b6d7 100644
--- a/third_party/blink/renderer/modules/sensor/sensor_proxy.cc
+++ b/third_party/blink/renderer/modules/sensor/sensor_proxy.cc
@@ -115,10 +115,11 @@
     return true;
 
   LocalFrame* focused_frame = GetPage()->GetFocusController().FocusedFrame();
-  if (!focused_frame)
+  LocalFrame* this_frame = provider_->GetSupplementable()->GetFrame();
+
+  if (!focused_frame || !this_frame)
     return true;
 
-  LocalFrame* this_frame = provider_->GetSupplementable()->GetFrame();
   if (focused_frame == this_frame)
     return false;
 
diff --git a/third_party/blink/renderer/modules/vr/navigator_vr.idl b/third_party/blink/renderer/modules/vr/navigator_vr.idl
index 133163db..7e7fc582 100644
--- a/third_party/blink/renderer/modules/vr/navigator_vr.idl
+++ b/third_party/blink/renderer/modules/vr/navigator_vr.idl
@@ -10,5 +10,5 @@
     [SecureContext, OriginTrialEnabled=WebXR, MeasureAs=NavigatorXR] readonly attribute XR xr;
 
     // Legacy API
-    [RuntimeEnabled=WebVR, CallWith=ScriptState] Promise getVRDisplays();
+    [OriginTrialEnabled=WebVR, CallWith=ScriptState] Promise getVRDisplays();
 };
diff --git a/third_party/blink/renderer/modules/vr/vr_display.idl b/third_party/blink/renderer/modules/vr/vr_display.idl
index 2076430..026d6ce 100644
--- a/third_party/blink/renderer/modules/vr/vr_display.idl
+++ b/third_party/blink/renderer/modules/vr/vr_display.idl
@@ -10,7 +10,7 @@
 // https://w3c.github.io/webvr/#interface-vrdisplay
 [
     ActiveScriptWrappable,
-    RuntimeEnabled=WebVR
+    OriginTrialEnabled=WebVR
 ] interface VRDisplay : EventTarget {
     // An identifier for this device unique across VRDisplays.
     readonly attribute unsigned long displayId;
diff --git a/third_party/blink/renderer/modules/vr/vr_display_capabilities.idl b/third_party/blink/renderer/modules/vr/vr_display_capabilities.idl
index 78cd1f5..14d8265 100644
--- a/third_party/blink/renderer/modules/vr/vr_display_capabilities.idl
+++ b/third_party/blink/renderer/modules/vr/vr_display_capabilities.idl
@@ -4,7 +4,7 @@
 
 // https://w3c.github.io/webvr/#interface-vrdisplaycapabilities
 [
-    RuntimeEnabled=WebVR
+    OriginTrialEnabled=WebVR
 ] interface VRDisplayCapabilities {
   // Whether or not the VR display is capable of reporting user position.
   // If false position may still be reported using simulated values like
diff --git a/third_party/blink/renderer/modules/vr/vr_display_event.idl b/third_party/blink/renderer/modules/vr/vr_display_event.idl
index 5627279..ae9103a 100644
--- a/third_party/blink/renderer/modules/vr/vr_display_event.idl
+++ b/third_party/blink/renderer/modules/vr/vr_display_event.idl
@@ -12,7 +12,7 @@
 
 // https://w3c.github.io/webvr/#interface-vrdisplayevent
 [
-    RuntimeEnabled=WebVR,
+    OriginTrialEnabled=WebVR,
     Constructor(DOMString type, optional VRDisplayEventInit eventInitDict)
 ] interface VRDisplayEvent : Event {
     readonly attribute VRDisplay display;
diff --git a/third_party/blink/renderer/modules/vr/vr_eye_parameters.idl b/third_party/blink/renderer/modules/vr/vr_eye_parameters.idl
index 4da215c..7b5b630 100644
--- a/third_party/blink/renderer/modules/vr/vr_eye_parameters.idl
+++ b/third_party/blink/renderer/modules/vr/vr_eye_parameters.idl
@@ -4,7 +4,7 @@
 
 // https://w3c.github.io/webvr/#interface-vreyeparameters
 [
-    RuntimeEnabled=WebVR
+    OriginTrialEnabled=WebVR
 ] interface VREyeParameters {
   /* These values will vary after a FOV has been set */
   [DeprecateAs=VREyeParametersOffset] readonly attribute Float32Array offset;
diff --git a/third_party/blink/renderer/modules/vr/vr_frame_data.idl b/third_party/blink/renderer/modules/vr/vr_frame_data.idl
index 9df122c..5d1f348 100644
--- a/third_party/blink/renderer/modules/vr/vr_frame_data.idl
+++ b/third_party/blink/renderer/modules/vr/vr_frame_data.idl
@@ -4,7 +4,7 @@
 
 // https://w3c.github.io/webvr/#interface-vrframedata
 [
-    RuntimeEnabled=WebVR,
+    OriginTrialEnabled=WebVR,
     Constructor
 ] interface VRFrameData {
     readonly attribute Float32Array leftProjectionMatrix;
diff --git a/third_party/blink/renderer/modules/vr/vr_pose.idl b/third_party/blink/renderer/modules/vr/vr_pose.idl
index e8dcd63..e935c5f 100644
--- a/third_party/blink/renderer/modules/vr/vr_pose.idl
+++ b/third_party/blink/renderer/modules/vr/vr_pose.idl
@@ -4,7 +4,7 @@
 
 // https://w3c.github.io/webvr/#interface-vrpose
 [
-    RuntimeEnabled=WebVR
+    OriginTrialEnabled=WebVR
 ] interface VRPose {
     readonly attribute Float32Array? position;
     [MeasureAs=VRPoseLinearVelocity] readonly attribute Float32Array? linearVelocity;
diff --git a/third_party/blink/renderer/modules/vr/vr_stage_parameters.idl b/third_party/blink/renderer/modules/vr/vr_stage_parameters.idl
index 562c9b5a..458582f 100644
--- a/third_party/blink/renderer/modules/vr/vr_stage_parameters.idl
+++ b/third_party/blink/renderer/modules/vr/vr_stage_parameters.idl
@@ -4,7 +4,7 @@
 
 // https://w3c.github.io/webvr/#interface-vrstageparameters
 [
-    RuntimeEnabled=WebVR
+    OriginTrialEnabled=WebVR
 ] interface VRStageParameters {
   // A 16 element array containing the components of a 4x4 transform
   // matrix.  This matrix transforms the sitting space position
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 07dc7fab9..9092649 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -538,6 +538,7 @@
     },
     {
       name: "GamepadExtensions",
+      origin_trial_feature_name: "WebVR1.1M62",
       status: "experimental",
     },
     {
@@ -1363,6 +1364,7 @@
     },
     {
       name: "WebVR",
+      origin_trial_feature_name: "WebVR1.1M62",
       status: "experimental",
     },
     {
diff --git a/third_party/blink/tools/blinkpy/common/net/buildbot.py b/third_party/blink/tools/blinkpy/common/net/buildbot.py
index 72bd6012..5612f466 100644
--- a/third_party/blink/tools/blinkpy/common/net/buildbot.py
+++ b/third_party/blink/tools/blinkpy/common/net/buildbot.py
@@ -39,6 +39,8 @@
 
 RESULTS_URL_BASE = 'https://test-results.appspot.com/data/layout_results'
 
+DEFAULT_STEP_NAME = 'webkit_layout_tests (with patch)'
+
 
 class Build(collections.namedtuple('Build', ('builder_name', 'build_number'))):
     """Represents a combination of builder and build number.
@@ -58,7 +60,8 @@
         https://www.chromium.org/developers/the-json-test-results-format
     """
 
-    def results_url(self, builder_name, build_number=None):
+    def results_url(self, builder_name, build_number=None,
+                    step_name=DEFAULT_STEP_NAME):
         """Returns a URL for one set of archived layout test results.
 
         If a build number is given, this will be results for a particular run;
@@ -66,9 +69,11 @@
         the latest results.
         """
         if build_number:
-            assert str(build_number).isdigit(), 'expected numeric build number, got %s' % build_number
+            assert str(build_number).isdigit(), (
+                'expected numeric build number, got %s' % build_number)
             url_base = self.builder_results_url_base(builder_name)
-            return '%s/%s/layout-test-results' % (url_base, build_number)
+            return '%s/%s/%s/layout-test-results' % (
+                url_base, build_number, step_name)
         return self.accumulated_results_url_base(builder_name)
 
     def builder_results_url_base(self, builder_name):
@@ -81,7 +86,7 @@
         return '%s/%s' % (RESULTS_URL_BASE, re.sub('[ .()]', '_', builder_name))
 
     @memoized
-    def fetch_retry_summary_json(self, build):
+    def fetch_retry_summary_json(self, build, step_name=DEFAULT_STEP_NAME):
         """Fetches and returns the text of the archived retry_summary file.
 
         This file is expected to contain the results of retrying layout tests
@@ -89,7 +94,9 @@
         that failed only with the patch ("failures"), and tests that failed
         both with and without ("ignored").
         """
-        url_base = '%s/%s' % (self.builder_results_url_base(build.builder_name), build.build_number)
+        url_base = '%s/%s/%s' % (
+            self.builder_results_url_base(build.builder_name),
+            build.build_number, step_name)
         return NetworkTransaction(return_none_on_404=True).run(
             lambda: self.fetch_file(url_base, 'retry_summary.json'))
 
diff --git a/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py b/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py
index 0ca913f..dd7d4707 100644
--- a/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py
+++ b/third_party/blink/tools/blinkpy/common/net/buildbot_unittest.py
@@ -46,7 +46,8 @@
     def test_results_url_with_build_number(self):
         self.assertEqual(
             BuildBot().results_url('Test Builder', 10),
-            'https://test-results.appspot.com/data/layout_results/Test_Builder/10/layout-test-results')
+            'https://test-results.appspot.com/data/layout_results/Test_Builder/'
+            '10/webkit_layout_tests (with patch)/layout-test-results')
 
     def test_results_url_with_non_numeric_build_number(self):
         with self.assertRaisesRegexp(AssertionError, 'expected numeric build number'):
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
index ad54660..88b71bcd 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl.py
@@ -61,6 +61,10 @@
                 help=('Comma-separated-list of builders to pull new baselines '
                       'from (can also be provided multiple times).')),
             optparse.make_option(
+                '--step-name', default='webkit_layout_tests (with patch)',
+                help=('Layout test step name to fetch results from. Defaults '
+                      ' to \'webkit_layout_tests (with patch)\'.')),
+            optparse.make_option(
                 '--patchset', default=None,
                 help='Patchset number to fetch new baselines from.'),
             self.no_optimize_option,
@@ -106,7 +110,7 @@
             self.trigger_try_jobs(builders_with_no_jobs)
             return 1
 
-        jobs_to_results = self._fetch_results(jobs)
+        jobs_to_results = self._fetch_results(jobs, options.step_name)
 
         builders_with_results = {b.builder_name for b in jobs_to_results}
         builders_without_results = set(self.selected_try_bots) - builders_with_results
@@ -210,7 +214,7 @@
         for builder in sorted(builders):
             _log.info('  %s', builder)
 
-    def _fetch_results(self, jobs):
+    def _fetch_results(self, jobs, step_name):
         """Fetches results for all of the given builds.
 
         There should be a one-to-one correspondence between Builds, supported
@@ -221,6 +225,7 @@
 
         Args:
             jobs: A dict mapping Build objects to TryJobStatus objects.
+            step_name: The step name to fetch when retrieving test results.
 
         Returns:
             A dict mapping Build to LayoutTestResults for all completed jobs.
@@ -237,7 +242,8 @@
                 # Only completed failed builds will contain actual failed
                 # layout tests to download baselines for.
                 continue
-            results_url = buildbot.results_url(build.builder_name, build.build_number)
+            results_url = buildbot.results_url(
+                build.builder_name, build.build_number, step_name)
             layout_test_results = buildbot.fetch_results(build)
             if layout_test_results is None:
                 _log.info('Failed to fetch results for "%s".', build.builder_name)
diff --git a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
index e3d0e23..d9acbb2 100644
--- a/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
+++ b/third_party/blink/tools/blinkpy/tool/commands/rebaseline_cl_unittest.py
@@ -119,6 +119,7 @@
             'verbose': False,
             'builders': [],
             'patchset': None,
+            'step_name': 'webkit_layout_tests (with patch)',
         }
         options.update(kwargs)
         return optparse.Values(dict(**options))
@@ -411,7 +412,7 @@
             'INFO: Finished try jobs found for all try bots.\n',
             'INFO: Failed to fetch results for "MOCK Try Win".\n',
             ('INFO: Results URL: https://test-results.appspot.com/data/layout_results'
-             '/MOCK_Try_Win/5000/layout-test-results/results.html\n'),
+             '/MOCK_Try_Win/5000/webkit_layout_tests (with patch)/layout-test-results/results.html\n'),
             'INFO: There are some builders with no results:\n',
             'INFO:   MOCK Try Win\n',
             'INFO: Would you like to continue?\n',
@@ -428,7 +429,7 @@
             'INFO: Finished try jobs found for all try bots.\n',
             'INFO: Failed to fetch results for "MOCK Try Win".\n',
             ('INFO: Results URL: https://test-results.appspot.com/data/layout_results'
-             '/MOCK_Try_Win/5000/layout-test-results/results.html\n'),
+             '/MOCK_Try_Win/5000/webkit_layout_tests (with patch)/layout-test-results/results.html\n'),
             'INFO: There are some builders with no results:\n',
             'INFO:   MOCK Try Win\n',
             'INFO: For one/flaky-fail.html:\n',
diff --git a/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py b/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py
index 27c1f85..fa09766 100644
--- a/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py
+++ b/third_party/blink/tools/blinkpy/web_tests/try_flag_unittest.py
@@ -134,7 +134,7 @@
         TryFlag(cmd, host, MockGitCL(host, self.mock_try_results)).run()
 
         def results_url(build):
-            return '%s/%s/%s/layout-test-results/results.html' % (
+            return '%s/%s/%s/webkit_layout_tests (with patch)/layout-test-results/results.html' % (
                 'https://test-results.appspot.com/data/layout_results',
                 build.builder_name,
                 build.build_number
diff --git a/third_party/boringssl/roll_boringssl.py b/third_party/boringssl/roll_boringssl.py
index 9f78971..4753d93 100755
--- a/third_party/boringssl/roll_boringssl.py
+++ b/third_party/boringssl/roll_boringssl.py
@@ -56,6 +56,38 @@
     f.write(contents)
 
 
+def Log(repo, revspec):
+  """Returns the commits in |repo| covered by |revspec|."""
+  data = subprocess.check_output(['git', 'log', '--pretty=raw', revspec],
+                                 cwd=repo)
+  commits = []
+  chunks = data.split('\n\n')
+  if len(chunks) % 2 != 0:
+    raise ValueError('Invalid log format')
+  for i in range(0, len(chunks), 2):
+    commit = {}
+    # Parse commit properties.
+    for line in chunks[i].split('\n'):
+      name, value = line.split(' ', 1)
+      commit[name] = value
+    if 'commit' not in commit:
+      raise ValueError('Missing commit line')
+    # Parse commit message.
+    message = ""
+    lines = chunks[i+1].split('\n')
+    # Removing the trailing empty entry.
+    if lines and not lines[-1]:
+      lines.pop()
+    for line in lines:
+      INDENT = '    '
+      if not line.startswith(INDENT):
+        raise ValueError('Missing indent')
+      message += line[len(INDENT):] + '\n'
+    commit['message'] = message
+    commits.append(commit)
+  return commits
+
+
 def main():
   if len(sys.argv) > 2:
     sys.stderr.write('Usage: %s [COMMIT]' % sys.argv[0])
@@ -69,22 +101,39 @@
     return 0
 
   if len(sys.argv) > 1:
-    commit = RevParse(BORINGSSL_SRC_PATH, sys.argv[1])
+    new_head = RevParse(BORINGSSL_SRC_PATH, sys.argv[1])
   else:
     subprocess.check_call(['git', 'fetch', 'origin'], cwd=BORINGSSL_SRC_PATH)
-    commit = RevParse(BORINGSSL_SRC_PATH, 'origin/master')
+    new_head = RevParse(BORINGSSL_SRC_PATH, 'origin/master')
 
-  head = RevParse(BORINGSSL_SRC_PATH, 'HEAD')
-  if head == commit:
+  old_head = RevParse(BORINGSSL_SRC_PATH, 'HEAD')
+  if old_head == new_head:
     print 'BoringSSL already up to date.'
     return 0
 
-  print 'Rolling BoringSSL from %s to %s...' % (head, commit)
+  print 'Rolling BoringSSL from %s to %s...' % (old_head, new_head)
 
-  UpdateDEPS(DEPS_PATH, head, commit)
+  # Look for commits with associated Chromium bugs.
+  crbugs = set()
+  crbug_commits = []
+  log = Log(BORINGSSL_SRC_PATH, '%s..%s' % (old_head, new_head))
+  for commit in log:
+    has_bugs = False
+    for line in commit['message'].split('\n'):
+      lower = line.lower()
+      if lower.startswith('bug:') or lower.startswith('bug='):
+        for bug in lower[4:].split(','):
+          bug = bug.strip()
+          if bug.startswith('chromium:'):
+            crbugs.add(int(bug[len('chromium:'):]))
+            has_bugs = True
+    if has_bugs:
+      crbug_commits.append(commit)
+
+  UpdateDEPS(DEPS_PATH, old_head, new_head)
 
   # Checkout third_party/boringssl/src to generate new files.
-  subprocess.check_call(['git', 'checkout', commit], cwd=BORINGSSL_SRC_PATH)
+  subprocess.check_call(['git', 'checkout', new_head], cwd=BORINGSSL_SRC_PATH)
 
   # Clear the old generated files.
   for (osname, arch, _, _, _) in generate_build_files.OS_ARCH_COMBOS:
@@ -114,12 +163,23 @@
 
 https://boringssl.googlesource.com/boringssl/+log/%s..%s
 
-BUG=none
-""" % (head[:9], commit[:9], head, commit)
+""" % (old_head[:9], new_head[:9], old_head, new_head)
+  if crbug_commits:
+    message += 'The following commits have Chromium bugs associated:\n'
+    for commit in crbug_commits:
+      rev = commit['commit'][:9]
+      line, _ = commit['message'].split('\n', 1)
+      message += '  %s %s\n' % (rev, line)
+    message += '\n'
+  if crbugs:
+    message += 'Bug: %s\n' % (', '.join(str(bug) for bug in sorted(crbugs)),)
+  else:
+    message += 'Bug: none\n'
+
   subprocess.check_call(['git', 'commit', '-m', message], cwd=SRC_PATH)
 
   # Print update notes.
-  notes = subprocess.check_output(['git', 'log', '--grep', '^Update-Note:', '-i', '%s..%s' % (head, commit)], cwd=BORINGSSL_SRC_PATH).strip()
+  notes = subprocess.check_output(['git', 'log', '--grep', '^Update-Note:', '-i', '%s..%s' % (old_head, new_head)], cwd=BORINGSSL_SRC_PATH).strip()
   if len(notes) > 0:
     print "\x1b[1mThe following changes contain updating notes\x1b[0m:\n\n"
     print notes
diff --git a/third_party/tcmalloc/chromium/src/common.cc b/third_party/tcmalloc/chromium/src/common.cc
index 7c05a8b4..7b9b53e 100644
--- a/third_party/tcmalloc/chromium/src/common.cc
+++ b/third_party/tcmalloc/chromium/src/common.cc
@@ -38,6 +38,10 @@
 #include "base/spinlock.h"
 #include "getenv_safe.h" // TCMallocGetenvSafe
 
+#if defined(HAVE_UNISTD_H) && defined(HAVE_GETPAGESIZE)
+#include <unistd.h>  // for getpagesize
+#endif
+
 namespace tcmalloc {
 
 // Define the maximum number of object per classe type to transfer between
@@ -235,7 +239,8 @@
 
 // Metadata allocator -- keeps stats about how many bytes allocated.
 static uint64_t metadata_system_bytes_ = 0;
-static const size_t kMetadataAllocChunkSize = 8*1024*1024;
+
+static const size_t kMetadataAllocChunkSize = 8 * 1024 * 1024;
 // As ThreadCache objects are allocated with MetaDataAlloc, and also
 // CACHELINE_ALIGNED, we must use the same alignment as TCMalloc_SystemAlloc.
 static const size_t kMetadataAllignment = sizeof(MemoryAligner);
@@ -246,11 +251,23 @@
 static SpinLock metadata_alloc_lock(SpinLock::LINKER_INITIALIZED);
 
 void* MetaDataAlloc(size_t bytes) {
-  if (bytes >= kMetadataAllocChunkSize) {
-    void *rv = TCMalloc_SystemAlloc(bytes,
-                                    NULL, kMetadataAllignment);
+  static size_t pagesize;
+#ifdef HAVE_GETPAGESIZE
+  if (pagesize == 0)
+    pagesize = getpagesize();
+#endif
+
+  if (bytes + pagesize >= kMetadataAllocChunkSize) {
+    void* rv = TCMalloc_SystemAlloc(bytes + pagesize, NULL, pagesize);
     if (rv != NULL) {
-      metadata_system_bytes_ += bytes;
+      metadata_system_bytes_ += bytes + pagesize;
+
+      // This guard page protects the metadata from being corrupted by a
+      // buffer overrun. We currently have no mechanism for freeing it, since
+      // we never release the metadata buffer. If that changes we'll need to
+      // add something like TCMalloc_SystemRemoveGuard.
+      TCMalloc_SystemAddGuard(rv, bytes + pagesize);
+      rv = static_cast<void*>(static_cast<char*>(rv) + pagesize);
     }
     return rv;
   }
@@ -266,14 +283,16 @@
 
   if (metadata_chunk_avail_ < bytes + alignment) {
     size_t real_size;
-    void *ptr = TCMalloc_SystemAlloc(kMetadataAllocChunkSize,
-                                     &real_size, kMetadataAllignment);
+    void* ptr =
+        TCMalloc_SystemAlloc(kMetadataAllocChunkSize, &real_size, pagesize);
     if (ptr == NULL) {
       return NULL;
     }
 
-    metadata_chunk_alloc_ = static_cast<char *>(ptr);
-    metadata_chunk_avail_ = real_size;
+    TCMalloc_SystemAddGuard(ptr, kMetadataAllocChunkSize);
+    metadata_chunk_alloc_ = static_cast<char*>(ptr) + pagesize;
+    metadata_chunk_avail_ = real_size - pagesize;
+    metadata_system_bytes_ += pagesize;
 
     alignment = 0;
   }
diff --git a/third_party/tcmalloc/chromium/src/common.h b/third_party/tcmalloc/chromium/src/common.h
index 7738694..7ad83d3 100644
--- a/third_party/tcmalloc/chromium/src/common.h
+++ b/third_party/tcmalloc/chromium/src/common.h
@@ -305,9 +305,9 @@
   }
 };
 
-// Allocates "bytes" worth of memory and returns it.  Increments
-// metadata_system_bytes appropriately.  May return NULL if allocation
-// fails.  Requires pageheap_lock is held.
+// Allocates "bytes" worth of memory with a guard page in front and
+// returns it.  Increments metadata_system_bytes appropriately.  May
+// return NULL if allocation fails.  Requires pageheap_lock is held.
 void* MetaDataAlloc(size_t bytes);
 
 // Returns the total number of bytes allocated from the system.
diff --git a/third_party/tcmalloc/chromium/src/system-alloc.cc b/third_party/tcmalloc/chromium/src/system-alloc.cc
index 235ccb1..52dd142 100644
--- a/third_party/tcmalloc/chromium/src/system-alloc.cc
+++ b/third_party/tcmalloc/chromium/src/system-alloc.cc
@@ -94,6 +94,7 @@
 #endif
 
 // TODO(sanjay): Move the code below into the tcmalloc namespace
+using tcmalloc::kCrash;
 using tcmalloc::kLog;
 using tcmalloc::Log;
 
@@ -250,9 +251,10 @@
 static SpinLock spinlock(SpinLock::LINKER_INITIALIZED);
 
 #if defined(HAVE_MMAP) || defined(MADV_FREE)
-// Page size is initialized on demand (only needed for mmap-based allocators)
+#ifdef HAVE_GETPAGESIZE
 static size_t pagesize = 0;
 #endif
+#endif
 
 // The current system allocator
 SysAllocator* tcmalloc_sys_alloc = NULL;
@@ -660,6 +662,27 @@
   return result;
 }
 
+void TCMalloc_SystemAddGuard(void* start, size_t size) {
+#ifdef HAVE_GETPAGESIZE
+  if (pagesize == 0)
+    pagesize = getpagesize();
+
+  if (size < pagesize || (reinterpret_cast<size_t>(start) % pagesize) != 0) {
+    Log(kCrash, __FILE__, __LINE__,
+        "FATAL ERROR: alloc size (%d) < pagesize (%d), or start address (%p) "
+        "is not page aligned\n",
+        size, pagesize, start);
+    return;
+  }
+
+  if (mprotect(start, pagesize, PROT_NONE)) {
+    Log(kCrash, __FILE__, __LINE__,
+        "FATAL ERROR: mprotect(%p, %d, PROT_NONE) failed: %s\n", start,
+        pagesize, strerror(errno));
+  }
+#endif
+}
+
 bool TCMalloc_SystemRelease(void* start, size_t length) {
 #ifdef MADV_FREE
   if (FLAGS_malloc_devmem_start) {
diff --git a/third_party/tcmalloc/chromium/src/system-alloc.h b/third_party/tcmalloc/chromium/src/system-alloc.h
index 655d470..2471f21 100644
--- a/third_party/tcmalloc/chromium/src/system-alloc.h
+++ b/third_party/tcmalloc/chromium/src/system-alloc.h
@@ -83,6 +83,10 @@
 extern PERFTOOLS_DLL_DECL
 void TCMalloc_SystemCommit(void* start, size_t length);
 
+// Guards the first page in the supplied range of memory. It crashes the
+// program if the guard page cannot be added.
+extern void TCMalloc_SystemAddGuard(void* start, size_t size);
+
 // The current system allocator.
 extern PERFTOOLS_DLL_DECL SysAllocator* tcmalloc_sys_alloc;
 
diff --git a/third_party/webdriver/README.chromium b/third_party/webdriver/README.chromium
index 1b97043b7..839fd44 100644
--- a/third_party/webdriver/README.chromium
+++ b/third_party/webdriver/README.chromium
@@ -18,7 +18,7 @@
   atoms.h, atoms.cc
     These atoms are generated by the webdriver team and are to be checked in
     manually. The current version was generated from revision
-    381f815652933f7077762ffba5f18794ab88c9b5.
+    a3444b8f4dbb6e83b8710455e6d8352439ac1874.
 
     To generate the atoms using the code found in selenium tree:
       $ git clone https://github.com/SeleniumHQ/selenium.git
diff --git a/third_party/webdriver/atoms.cc b/third_party/webdriver/atoms.cc
index 21affc8..6a8e9fc 100644
--- a/third_party/webdriver/atoms.cc
+++ b/third_party/webdriver/atoms.cc
@@ -60,16 +60,16 @@
     ",c){return c.toUpperCase()})};function oa(a,b){if(l(a))return l(b)&&1==",
     "b.length?a.indexOf(b,0):-1;for(var c=0;c<a.length;c++)if(c in a&&a[c]==",
     "=b)return c;return-1}function q(a,b){for(var c=a.length,d=l(a)?a.split(",
-    "\"\"):a,e=0;e<c;e++)e in d&&b.call(void 0,d[e],e,a)}function r(a,b,c){v",
-    "ar d=c;q(a,function(c,f){d=b.call(void 0,d,c,f,a)});return d}function u",
-    "(a,b){for(var c=a.length,d=l(a)?a.split(\"\"):a,e=0;e<c;e++)if(e in d&&",
-    "b.call(void 0,d[e],e,a))return!0;return!1}\nfunction pa(a,b){for(var c=",
-    "a.length,d=l(a)?a.split(\"\"):a,e=0;e<c;e++)if(e in d&&!b.call(void 0,d",
-    "[e],e,a))return!1;return!0}function qa(a){return Array.prototype.concat",
-    ".apply([],arguments)}function ra(a){var b=a.length;if(0<b){for(var c=Ar",
-    "ray(b),d=0;d<b;d++)c[d]=a[d];return c}return[]}function sa(a,b,c){retur",
-    "n 2>=arguments.length?Array.prototype.slice.call(a,b):Array.prototype.s",
-    "lice.call(a,b,c)};var ta={aliceblue:\"#f0f8ff\",antiquewhite:\"#faebd7",
+    "\"\"):a,e=0;e<c;e++)e in d&&b.call(void 0,d[e],e,a)}function pa(a,b,c){",
+    "var d=c;q(a,function(c,f){d=b.call(void 0,d,c,f,a)});return d}function ",
+    "r(a,b){for(var c=a.length,d=l(a)?a.split(\"\"):a,e=0;e<c;e++)if(e in d&",
+    "&b.call(void 0,d[e],e,a))return!0;return!1}\nfunction qa(a,b){for(var c",
+    "=a.length,d=l(a)?a.split(\"\"):a,e=0;e<c;e++)if(e in d&&!b.call(void 0,",
+    "d[e],e,a))return!1;return!0}function ra(a){return Array.prototype.conca",
+    "t.apply([],arguments)}function sa(a){var b=a.length;if(0<b){for(var c=A",
+    "rray(b),d=0;d<b;d++)c[d]=a[d];return c}return[]}function ta(a,b,c){retu",
+    "rn 2>=arguments.length?Array.prototype.slice.call(a,b):Array.prototype.",
+    "slice.call(a,b,c)};var ua={aliceblue:\"#f0f8ff\",antiquewhite:\"#faebd7",
     "\",aqua:\"#00ffff\",aquamarine:\"#7fffd4\",azure:\"#f0ffff\",beige:\"#f",
     "5f5dc\",bisque:\"#ffe4c4\",black:\"#000000\",blanchedalmond:\"#ffebcd\"",
     ",blue:\"#0000ff\",blueviolet:\"#8a2be2\",brown:\"#a52a2a\",burlywood:\"",
@@ -115,83 +115,83 @@
     "d2b48c\",teal:\"#008080\",thistle:\"#d8bfd8\",tomato:\"#ff6347\",turquo",
     "ise:\"#40e0d0\",violet:\"#ee82ee\",wheat:\"#f5deb3\",white:\"#ffffff\",",
     "whitesmoke:\"#f5f5f5\",yellow:\"#ffff00\",yellowgreen:\"#9acd32\"};var ",
-    "ua=\"backgroundColor borderTopColor borderRightColor borderBottomColor ",
-    "borderLeftColor color outlineColor\".split(\" \"),va=/#([0-9a-fA-F])([0",
-    "-9a-fA-F])([0-9a-fA-F])/,wa=/^#(?:[0-9a-f]{3}){1,2}$/i,xa=/^(?:rgba)?",
-    "\\((\\d{1,3}),\\s?(\\d{1,3}),\\s?(\\d{1,3}),\\s?(0|1|0\\.\\d*)\\)$/i,ya",
+    "va=\"backgroundColor borderTopColor borderRightColor borderBottomColor ",
+    "borderLeftColor color outlineColor\".split(\" \"),wa=/#([0-9a-fA-F])([0",
+    "-9a-fA-F])([0-9a-fA-F])/,xa=/^#(?:[0-9a-f]{3}){1,2}$/i,ya=/^(?:rgba)?",
+    "\\((\\d{1,3}),\\s?(\\d{1,3}),\\s?(\\d{1,3}),\\s?(0|1|0\\.\\d*)\\)$/i,za",
     "=/^(?:rgb)?\\((0|[1-9]\\d{0,2}),\\s?(0|[1-9]\\d{0,2}),\\s?(0|[1-9]\\d{0",
-    ",2})\\)$/i;function v(a,b){this.code=a;this.state=w[a]||za;this.message",
+    ",2})\\)$/i;function u(a,b){this.code=a;this.state=v[a]||Aa;this.message",
     "=b||\"\";a=this.state.replace(/((?:^|\\s+)[a-z])/g,function(a){return a",
     ".toUpperCase().replace(/^[\\s\\xa0]+/g,\"\")});b=a.length-5;if(0>b||a.i",
     "ndexOf(\"Error\",b)!=b)a+=\"Error\";this.name=a;a=Error(this.message);a",
-    ".name=this.name;this.stack=a.stack||\"\"}p(v,Error);var za=\"unknown er",
-    "ror\",w={15:\"element not selectable\",11:\"element not visible\"};w[31",
-    "]=za;w[30]=za;w[24]=\"invalid cookie domain\";w[29]=\"invalid element c",
-    "oordinates\";w[12]=\"invalid element state\";\nw[32]=\"invalid selector",
-    "\";w[51]=\"invalid selector\";w[52]=\"invalid selector\";w[17]=\"javasc",
-    "ript error\";w[405]=\"unsupported operation\";w[34]=\"move target out o",
-    "f bounds\";w[27]=\"no such alert\";w[7]=\"no such element\";w[8]=\"no s",
-    "uch frame\";w[23]=\"no such window\";w[28]=\"script timeout\";w[33]=\"s",
-    "ession not created\";w[10]=\"stale element reference\";w[21]=\"timeout",
-    "\";w[25]=\"unable to set cookie\";w[26]=\"unexpected alert open\";w[13]",
-    "=za;w[9]=\"unknown command\";v.prototype.toString=function(){return thi",
-    "s.name+\": \"+this.message};var Aa;a:{var Ba=aa.navigator;if(Ba){var Ca",
-    "=Ba.userAgent;if(Ca){Aa=Ca;break a}}Aa=\"\"};function Ea(a){var b=Fa;Ob",
+    ".name=this.name;this.stack=a.stack||\"\"}p(u,Error);var Aa=\"unknown er",
+    "ror\",v={15:\"element not selectable\",11:\"element not visible\"};v[31",
+    "]=Aa;v[30]=Aa;v[24]=\"invalid cookie domain\";v[29]=\"invalid element c",
+    "oordinates\";v[12]=\"invalid element state\";\nv[32]=\"invalid selector",
+    "\";v[51]=\"invalid selector\";v[52]=\"invalid selector\";v[17]=\"javasc",
+    "ript error\";v[405]=\"unsupported operation\";v[34]=\"move target out o",
+    "f bounds\";v[27]=\"no such alert\";v[7]=\"no such element\";v[8]=\"no s",
+    "uch frame\";v[23]=\"no such window\";v[28]=\"script timeout\";v[33]=\"s",
+    "ession not created\";v[10]=\"stale element reference\";v[21]=\"timeout",
+    "\";v[25]=\"unable to set cookie\";v[26]=\"unexpected alert open\";v[13]",
+    "=Aa;v[9]=\"unknown command\";u.prototype.toString=function(){return thi",
+    "s.name+\": \"+this.message};var Ba;a:{var Ca=aa.navigator;if(Ca){var Da",
+    "=Ca.userAgent;if(Da){Ba=Da;break a}}Ba=\"\"};function Fa(a){var b=Ga;Ob",
     "ject.prototype.hasOwnProperty.call(b,\"528\")||(b[\"528\"]=a(\"528\"))}",
-    ";var Ga=-1!=Aa.indexOf(\"Macintosh\"),Ha=-1!=Aa.indexOf(\"Windows\"),Ia",
-    ",Ja=\"\",Ka=/WebKit\\/(\\S+)/.exec(Aa);Ka&&(Ja=Ka?Ka[1]:\"\");Ia=Ja;var",
-    " Fa={};\nfunction La(){Ea(function(){for(var a=0,b=la(String(Ia)).split",
+    ";var Ha=-1!=Ba.indexOf(\"Macintosh\"),Ia=-1!=Ba.indexOf(\"Windows\"),Ja",
+    ",Ka=\"\",La=/WebKit\\/(\\S+)/.exec(Ba);La&&(Ka=La?La[1]:\"\");Ja=Ka;var",
+    " Ga={};\nfunction Ma(){Fa(function(){for(var a=0,b=la(String(Ja)).split",
     "(\".\"),c=la(\"528\").split(\".\"),d=Math.max(b.length,c.length),e=0;0=",
     "=a&&e<d;e++){var f=b[e]||\"\",h=c[e]||\"\";do{f=/(\\d*)(\\D*)(.*)/.exec",
     "(f)||[\"\",\"\",\"\",\"\"];h=/(\\d*)(\\D*)(.*)/.exec(h)||[\"\",\"\",\"",
     "\",\"\"];if(0==f[0].length&&0==h[0].length)break;a=ma(0==f[1].length?0:",
     "parseInt(f[1],10),0==h[1].length?0:parseInt(h[1],10))||ma(0==f[2].lengt",
     "h,0==h[2].length)||ma(f[2],h[2]);f=f[3];h=h[3]}while(0==a)}return 0<=a}",
-    ")};function x(a,b){this.x=k(a)?a:0;this.y=k(b)?b:0}g=x.prototype;g.clon",
-    "e=function(){return new x(this.x,this.y)};g.toString=function(){return",
+    ")};function w(a,b){this.x=k(a)?a:0;this.y=k(b)?b:0}g=w.prototype;g.clon",
+    "e=function(){return new w(this.x,this.y)};g.toString=function(){return",
     "\"(\"+this.x+\", \"+this.y+\")\"};g.ceil=function(){this.x=Math.ceil(th",
     "is.x);this.y=Math.ceil(this.y);return this};g.floor=function(){this.x=M",
     "ath.floor(this.x);this.y=Math.floor(this.y);return this};g.round=functi",
     "on(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this};",
-    "\ng.translate=function(a,b){a instanceof x?(this.x+=a.x,this.y+=a.y):(t",
+    "\ng.translate=function(a,b){a instanceof w?(this.x+=a.x,this.y+=a.y):(t",
     "his.x+=Number(a),n(b)&&(this.y+=b));return this};g.scale=function(a,b){",
-    "b=n(b)?b:a;this.x*=a;this.y*=b;return this};function Ma(a,b){this.width",
-    "=a;this.height=b}g=Ma.prototype;g.clone=function(){return new Ma(this.w",
+    "b=n(b)?b:a;this.x*=a;this.y*=b;return this};function Na(a,b){this.width",
+    "=a;this.height=b}g=Na.prototype;g.clone=function(){return new Na(this.w",
     "idth,this.height)};g.toString=function(){return\"(\"+this.width+\" x \"",
     "+this.height+\")\"};g.ceil=function(){this.width=Math.ceil(this.width);",
     "this.height=Math.ceil(this.height);return this};g.floor=function(){this",
     ".width=Math.floor(this.width);this.height=Math.floor(this.height);retur",
     "n this};g.round=function(){this.width=Math.round(this.width);this.heigh",
     "t=Math.round(this.height);return this};\ng.scale=function(a,b){b=n(b)?b",
-    ":a;this.width*=a;this.height*=b;return this};function Na(a,b,c){functio",
+    ":a;this.width*=a;this.height*=b;return this};function Oa(a,b,c){functio",
     "n d(c){c&&b.appendChild(l(c)?a.createTextNode(c):c)}for(var e=1;e<c.len",
-    "gth;e++){var f=c[e];!da(f)||fa(f)&&0<f.nodeType?d(f):q(Oa(f)?ra(f):f,d)",
-    "}}function Pa(a){for(;a&&1!=a.nodeType;)a=a.previousSibling;return a}fu",
-    "nction Qa(a,b){if(!a||!b)return!1;if(a.contains&&1==b.nodeType)return a",
+    "gth;e++){var f=c[e];!da(f)||fa(f)&&0<f.nodeType?d(f):q(Pa(f)?sa(f):f,d)",
+    "}}function Qa(a){for(;a&&1!=a.nodeType;)a=a.previousSibling;return a}fu",
+    "nction Ra(a,b){if(!a||!b)return!1;if(a.contains&&1==b.nodeType)return a",
     "==b||a.contains(b);if(\"undefined\"!=typeof a.compareDocumentPosition)r",
     "eturn a==b||!!(a.compareDocumentPosition(b)&16);for(;b&&a!=b;)b=b.paren",
-    "tNode;return b==a}\nfunction Ra(a,b){if(a==b)return 0;if(a.compareDocum",
+    "tNode;return b==a}\nfunction Sa(a,b){if(a==b)return 0;if(a.compareDocum",
     "entPosition)return a.compareDocumentPosition(b)&2?1:-1;if(\"sourceIndex",
     "\"in a||a.parentNode&&\"sourceIndex\"in a.parentNode){var c=1==a.nodeTy",
     "pe,d=1==b.nodeType;if(c&&d)return a.sourceIndex-b.sourceIndex;var e=a.p",
-    "arentNode,f=b.parentNode;return e==f?Sa(a,b):!c&&Qa(e,b)?-1*Ta(a,b):!d&",
-    "&Qa(f,a)?Ta(b,a):(c?a.sourceIndex:e.sourceIndex)-(d?b.sourceIndex:f.sou",
-    "rceIndex)}d=A(a);c=d.createRange();c.selectNode(a);c.collapse(!0);a=d.c",
+    "arentNode,f=b.parentNode;return e==f?Ta(a,b):!c&&Ra(e,b)?-1*Ua(a,b):!d&",
+    "&Ra(f,a)?Ua(b,a):(c?a.sourceIndex:e.sourceIndex)-(d?b.sourceIndex:f.sou",
+    "rceIndex)}d=x(a);c=d.createRange();c.selectNode(a);c.collapse(!0);a=d.c",
     "reateRange();a.selectNode(b);\na.collapse(!0);return c.compareBoundaryP",
-    "oints(aa.Range.START_TO_END,a)}function Ta(a,b){var c=a.parentNode;if(c",
-    "==b)return-1;for(;b.parentNode!=c;)b=b.parentNode;return Sa(b,a)}functi",
-    "on Sa(a,b){for(;b=b.previousSibling;)if(b==a)return-1;return 1}function",
-    " A(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function Oa(a)",
+    "oints(aa.Range.START_TO_END,a)}function Ua(a,b){var c=a.parentNode;if(c",
+    "==b)return-1;for(;b.parentNode!=c;)b=b.parentNode;return Ta(b,a)}functi",
+    "on Ta(a,b){for(;b=b.previousSibling;)if(b==a)return-1;return 1}function",
+    " x(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function Pa(a)",
     "{if(a&&\"number\"==typeof a.length){if(fa(a))return\"function\"==typeof",
     " a.item||\"string\"==typeof a.item;if(ea(a))return\"function\"==typeof ",
-    "a.item}return!1}\nfunction Ua(a,b,c){a&&!c&&(a=a.parentNode);for(c=0;a;",
-    "){if(b(a))return a;a=a.parentNode;c++}return null}function Va(a){try{re",
-    "turn a&&a.activeElement}catch(b){}return null}function Wa(a){this.M=a||",
-    "aa.document||document}g=Wa.prototype;g.getElementsByTagName=function(a,",
+    "a.item}return!1}\nfunction Va(a,b,c){a&&!c&&(a=a.parentNode);for(c=0;a;",
+    "){if(b(a))return a;a=a.parentNode;c++}return null}function Wa(a){try{re",
+    "turn a&&a.activeElement}catch(b){}return null}function Xa(a){this.M=a||",
+    "aa.document||document}g=Xa.prototype;g.getElementsByTagName=function(a,",
     "b){return(b||this.M).getElementsByTagName(String(a))};g.createElement=f",
     "unction(a){return this.M.createElement(String(a))};g.createTextNode=fun",
     "ction(a){return this.M.createTextNode(String(a))};g.appendChild=functio",
-    "n(a,b){a.appendChild(b)};\ng.append=function(a,b){Na(A(a),a,arguments)}",
+    "n(a,b){a.appendChild(b)};\ng.append=function(a,b){Oa(x(a),a,arguments)}",
     ";g.canHaveChildren=function(a){if(1!=a.nodeType)return!1;switch(a.tagNa",
     "me){case \"APPLET\":case \"AREA\":case \"BASE\":case \"BR\":case \"COL",
     "\":case \"COMMAND\":case \"EMBED\":case \"FRAME\":case \"HR\":case \"IM",
@@ -199,14 +199,14 @@
     "e \"LINK\":case \"NOFRAMES\":case \"NOSCRIPT\":case \"META\":case \"OBJ",
     "ECT\":case \"PARAM\":case \"SCRIPT\":case \"SOURCE\":case \"STYLE\":cas",
     "e \"TRACK\":case \"WBR\":return!1}return!0};\ng.removeNode=function(a){",
-    "return a&&a.parentNode?a.parentNode.removeChild(a):null};g.contains=Qa;",
-    "function Xa(a){var b=\"tabindex\";return\"style\"==b?Ya(a.style.cssText",
-    "):(a=a.getAttributeNode(b))&&a.specified?a.value:null}var Za=/[;]+(?=(?",
+    "return a&&a.parentNode?a.parentNode.removeChild(a):null};g.contains=Ra;",
+    "function Ya(a){var b=\"tabindex\";return\"style\"==b?Za(a.style.cssText",
+    "):(a=a.getAttributeNode(b))&&a.specified?a.value:null}var $a=/[;]+(?=(?",
     ":(?:[^\"]*\"){2})*[^\"]*$)(?=(?:(?:[^']*'){2})*[^']*$)(?=(?:[^()]*\\([^",
-    "()]*\\))*[^()]*$)/;function Ya(a){var b=[];q(a.split(Za),function(a){va",
+    "()]*\\))*[^()]*$)/;function Za(a){var b=[];q(a.split($a),function(a){va",
     "r c=a.indexOf(\":\");0<c&&(a=[a.slice(0,c),a.slice(c+1)],2==a.length&&b",
     ".push(a[0].toLowerCase(),\":\",a[1],\";\"))});b=b.join(\"\");return b=",
-    "\";\"==b.charAt(b.length-1)?b:b+\";\"}\nfunction B(a,b){b&&\"string\"!=",
+    "\";\"==b.charAt(b.length-1)?b:b+\";\"}\nfunction A(a,b){b&&\"string\"!=",
     "=typeof b&&(b=b.toString());return!!a&&1==a.nodeType&&(!b||a.tagName.to",
     "UpperCase()==b)};/*\n\n The MIT License\n\n Copyright (c) 2007 Cybozu L",
     "abs, Inc.\n Copyright (c) 2012 Google Inc.\n\n Permission is hereby gra",
@@ -224,537 +224,541 @@
     "ALL THE\n AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES",
     " OR OTHER\n LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERW",
     "ISE, ARISING\n FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE U",
-    "SE OR OTHER DEALINGS\n IN THE SOFTWARE.\n*/\nfunction $a(a,b,c){this.s=",
-    "a;this.ya=b||1;this.o=c||1};function ab(a){this.$=a;this.P=0}function b",
-    "b(a){a=a.match(cb);for(var b=0;b<a.length;b++)db.test(a[b])&&a.splice(b",
-    ",1);return new ab(a)}var cb=/\\$?(?:(?![0-9-\\.])(?:\\*|[\\w-\\.]+):)?(",
+    "SE OR OTHER DEALINGS\n IN THE SOFTWARE.\n*/\nfunction ab(a,b,c){this.s=",
+    "a;this.ya=b||1;this.o=c||1};function bb(a){this.$=a;this.P=0}function c",
+    "b(a){a=a.match(db);for(var b=0;b<a.length;b++)eb.test(a[b])&&a.splice(b",
+    ",1);return new bb(a)}var db=/\\$?(?:(?![0-9-\\.])(?:\\*|[\\w-\\.]+):)?(",
     "?![0-9-\\.])(?:\\*|[\\w-\\.]+)|\\/\\/|\\.\\.|::|\\d+(?:\\.\\d*)?|\\.\\d",
-    "+|\"[^\"]*\"|'[^']*'|[!<>]=|\\s+|./g,db=/^\\s/;function C(a,b){return a",
-    ".$[a.P+(b||0)]}ab.prototype.next=function(){return this.$[this.P++]};ab",
-    ".prototype.back=function(){this.P--};ab.prototype.empty=function(){retu",
-    "rn this.$.length<=this.P};function D(a){var b=null,c=a.nodeType;1==c&&(",
+    "+|\"[^\"]*\"|'[^']*'|[!<>]=|\\s+|./g,eb=/^\\s/;function B(a,b){return a",
+    ".$[a.P+(b||0)]}bb.prototype.next=function(){return this.$[this.P++]};bb",
+    ".prototype.back=function(){this.P--};bb.prototype.empty=function(){retu",
+    "rn this.$.length<=this.P};function C(a){var b=null,c=a.nodeType;1==c&&(",
     "b=a.textContent,b=void 0==b||null==b?a.innerText:b,b=void 0==b||null==b",
     "?\"\":b);if(\"string\"!=typeof b)if(9==c||1==c){a=9==c?a.documentElemen",
     "t:a.firstChild;for(var c=0,d=[],b=\"\";a;){do 1!=a.nodeType&&(b+=a.node",
     "Value),d[c++]=a;while(a=a.firstChild);for(;c&&!(a=d[--c].nextSibling);)",
-    ";}}else b=a.nodeValue;return\"\"+b}\nfunction eb(a,b,c){if(null===b)ret",
+    ";}}else b=a.nodeValue;return\"\"+b}\nfunction fb(a,b,c){if(null===b)ret",
     "urn!0;try{if(!a.getAttribute)return!1}catch(d){return!1}return null==c?",
-    "!!a.getAttribute(b):a.getAttribute(b,2)==c}function fb(a,b,c,d,e){retur",
-    "n gb.call(null,a,b,l(c)?c:null,l(d)?d:null,e||new E)}\nfunction gb(a,b,",
+    "!!a.getAttribute(b):a.getAttribute(b,2)==c}function gb(a,b,c,d,e){retur",
+    "n hb.call(null,a,b,l(c)?c:null,l(d)?d:null,e||new D)}\nfunction hb(a,b,",
     "c,d,e){b.getElementsByName&&d&&\"name\"==c?(b=b.getElementsByName(d),q(",
     "b,function(b){a.matches(b)&&e.add(b)})):b.getElementsByClassName&&d&&\"",
     "class\"==c?(b=b.getElementsByClassName(d),q(b,function(b){b.className==",
-    "d&&a.matches(b)&&e.add(b)})):a instanceof F?hb(a,b,c,d,e):b.getElements",
-    "ByTagName&&(b=b.getElementsByTagName(a.getName()),q(b,function(a){eb(a,",
-    "c,d)&&e.add(a)}));return e}\nfunction hb(a,b,c,d,e){for(b=b.firstChild;",
-    "b;b=b.nextSibling)eb(b,c,d)&&a.matches(b)&&e.add(b),hb(a,b,c,d,e)};func",
-    "tion E(){this.o=this.j=null;this.J=0}function ib(a){this.node=a;this.ne",
-    "xt=this.F=null}function jb(a,b){if(!a.j)return b;if(!b.j)return a;var c",
+    "d&&a.matches(b)&&e.add(b)})):a instanceof E?ib(a,b,c,d,e):b.getElements",
+    "ByTagName&&(b=b.getElementsByTagName(a.getName()),q(b,function(a){fb(a,",
+    "c,d)&&e.add(a)}));return e}\nfunction ib(a,b,c,d,e){for(b=b.firstChild;",
+    "b;b=b.nextSibling)fb(b,c,d)&&a.matches(b)&&e.add(b),ib(a,b,c,d,e)};func",
+    "tion D(){this.o=this.j=null;this.J=0}function jb(a){this.node=a;this.ne",
+    "xt=this.F=null}function kb(a,b){if(!a.j)return b;if(!b.j)return a;var c",
     "=a.j;b=b.j;for(var d=null,e,f=0;c&&b;)c.node==b.node?(e=c,c=c.next,b=b.",
-    "next):0<Ra(c.node,b.node)?(e=b,b=b.next):(e=c,c=c.next),(e.F=d)?d.next=",
+    "next):0<Sa(c.node,b.node)?(e=b,b=b.next):(e=c,c=c.next),(e.F=d)?d.next=",
     "e:a.j=e,d=e,f++;for(e=c||b;e;)e.F=d,d=d.next=e,f++,e=e.next;a.o=d;a.J=f",
-    ";return a}E.prototype.unshift=function(a){a=new ib(a);a.next=this.j;thi",
-    "s.o?this.j.F=a:this.j=this.o=a;this.j=a;this.J++};\nE.prototype.add=fun",
-    "ction(a){a=new ib(a);a.F=this.o;this.j?this.o.next=a:this.j=this.o=a;th",
-    "is.o=a;this.J++};function kb(a){return(a=a.j)?a.node:null}E.prototype.v",
-    "=function(){return this.J};function lb(a){return(a=kb(a))?D(a):\"\"}E.p",
-    "rototype.iterator=function(a){return new mb(this,!!a)};function mb(a,b)",
-    "{this.ua=a;this.ca=(this.H=b)?a.o:a.j;this.X=null}mb.prototype.next=fun",
+    ";return a}D.prototype.unshift=function(a){a=new jb(a);a.next=this.j;thi",
+    "s.o?this.j.F=a:this.j=this.o=a;this.j=a;this.J++};\nD.prototype.add=fun",
+    "ction(a){a=new jb(a);a.F=this.o;this.j?this.o.next=a:this.j=this.o=a;th",
+    "is.o=a;this.J++};function lb(a){return(a=a.j)?a.node:null}D.prototype.v",
+    "=function(){return this.J};function mb(a){return(a=lb(a))?C(a):\"\"}D.p",
+    "rototype.iterator=function(a){return new nb(this,!!a)};function nb(a,b)",
+    "{this.ua=a;this.ca=(this.H=b)?a.o:a.j;this.X=null}nb.prototype.next=fun",
     "ction(){var a=this.ca;if(null==a)return null;var b=this.X=a;this.ca=thi",
-    "s.H?a.F:a.next;return b.node};\nmb.prototype.remove=function(){var a=th",
+    "s.H?a.F:a.next;return b.node};\nnb.prototype.remove=function(){var a=th",
     "is.ua,b=this.X;if(!b)throw Error(\"Next must be called at least once be",
     "fore remove.\");var c=b.F,b=b.next;c?c.next=b:a.j=b;b?b.F=c:a.o=c;a.J--",
-    ";this.X=null};function G(a){this.i=a;this.l=this.A=!1;this.K=null}funct",
-    "ion I(a){return\"\\n  \"+a.toString().split(\"\\n\").join(\"\\n  \")}G.",
-    "prototype.h=function(){return this.A};function nb(a,b){a.A=b}function o",
-    "b(a,b){a.l=b}G.prototype.D=function(){return this.K};function J(a,b){a=",
-    "a.evaluate(b);return a instanceof E?+lb(a):+a}function K(a,b){a=a.evalu",
-    "ate(b);return a instanceof E?lb(a):\"\"+a}function pb(a,b){a=a.evaluate",
-    "(b);return a instanceof E?!!a.v():!!a};function qb(a,b,c){G.call(this,a",
+    ";this.X=null};function F(a){this.i=a;this.l=this.A=!1;this.K=null}funct",
+    "ion H(a){return\"\\n  \"+a.toString().split(\"\\n\").join(\"\\n  \")}F.",
+    "prototype.h=function(){return this.A};function ob(a,b){a.A=b}function p",
+    "b(a,b){a.l=b}F.prototype.D=function(){return this.K};function I(a,b){a=",
+    "a.evaluate(b);return a instanceof D?+mb(a):+a}function J(a,b){a=a.evalu",
+    "ate(b);return a instanceof D?mb(a):\"\"+a}function qb(a,b){a=a.evaluate",
+    "(b);return a instanceof D?!!a.v():!!a};function rb(a,b,c){F.call(this,a",
     ".i);this.Z=a;this.ga=b;this.la=c;this.A=b.h()||c.h();this.l=b.l||c.l;th",
-    "is.Z==rb&&(c.l||c.h()||4==c.i||0==c.i||!b.D()?b.l||b.h()||4==b.i||0==b.",
+    "is.Z==sb&&(c.l||c.h()||4==c.i||0==c.i||!b.D()?b.l||b.h()||4==b.i||0==b.",
     "i||!c.D()||(this.K={name:c.D().name,I:b}):this.K={name:b.D().name,I:c})",
-    "}p(qb,G);\nfunction sb(a,b,c,d,e){b=b.evaluate(d);c=c.evaluate(d);var f",
-    ";if(b instanceof E&&c instanceof E){b=b.iterator();for(d=b.next();d;d=b",
-    ".next())for(e=c.iterator(),f=e.next();f;f=e.next())if(a(D(d),D(f)))retu",
-    "rn!0;return!1}if(b instanceof E||c instanceof E){b instanceof E?(e=b,d=",
+    "}p(rb,F);\nfunction tb(a,b,c,d,e){b=b.evaluate(d);c=c.evaluate(d);var f",
+    ";if(b instanceof D&&c instanceof D){b=b.iterator();for(d=b.next();d;d=b",
+    ".next())for(e=c.iterator(),f=e.next();f;f=e.next())if(a(C(d),C(f)))retu",
+    "rn!0;return!1}if(b instanceof D||c instanceof D){b instanceof D?(e=b,d=",
     "c):(e=c,d=b);f=e.iterator();for(var h=typeof d,m=f.next();m;m=f.next())",
-    "{switch(h){case \"number\":m=+D(m);break;case \"boolean\":m=!!D(m);brea",
-    "k;case \"string\":m=D(m);break;default:throw Error(\"Illegal primitive ",
+    "{switch(h){case \"number\":m=+C(m);break;case \"boolean\":m=!!C(m);brea",
+    "k;case \"string\":m=C(m);break;default:throw Error(\"Illegal primitive ",
     "type for comparison.\");\n}if(e==b&&a(m,d)||e==c&&a(d,m))return!0}retur",
     "n!1}return e?\"boolean\"==typeof b||\"boolean\"==typeof c?a(!!b,!!c):\"",
-    "number\"==typeof b||\"number\"==typeof c?a(+b,+c):a(b,c):a(+b,+c)}qb.pr",
-    "ototype.evaluate=function(a){return this.Z.u(this.ga,this.la,a)};qb.pro",
-    "totype.toString=function(){var a=\"Binary Expression: \"+this.Z,a=a+I(t",
-    "his.ga);return a+=I(this.la)};function tb(a,b,c,d){this.xa=a;this.ja=b;",
-    "this.i=c;this.u=d}tb.prototype.toString=function(){return this.xa};var ",
-    "ub={};\nfunction L(a,b,c,d){if(ub.hasOwnProperty(a))throw Error(\"Binar",
-    "y operator already created: \"+a);a=new tb(a,b,c,d);return ub[a.toStrin",
-    "g()]=a}L(\"div\",6,1,function(a,b,c){return J(a,c)/J(b,c)});L(\"mod\",6",
-    ",1,function(a,b,c){return J(a,c)%J(b,c)});L(\"*\",6,1,function(a,b,c){r",
-    "eturn J(a,c)*J(b,c)});L(\"+\",5,1,function(a,b,c){return J(a,c)+J(b,c)}",
-    ");L(\"-\",5,1,function(a,b,c){return J(a,c)-J(b,c)});L(\"<\",4,2,functi",
-    "on(a,b,c){return sb(function(a,b){return a<b},a,b,c)});\nL(\">\",4,2,fu",
-    "nction(a,b,c){return sb(function(a,b){return a>b},a,b,c)});L(\"<=\",4,2",
-    ",function(a,b,c){return sb(function(a,b){return a<=b},a,b,c)});L(\">=\"",
-    ",4,2,function(a,b,c){return sb(function(a,b){return a>=b},a,b,c)});var ",
-    "rb=L(\"=\",3,2,function(a,b,c){return sb(function(a,b){return a==b},a,b",
-    ",c,!0)});L(\"!=\",3,2,function(a,b,c){return sb(function(a,b){return a!",
-    "=b},a,b,c,!0)});L(\"and\",2,2,function(a,b,c){return pb(a,c)&&pb(b,c)})",
-    ";L(\"or\",1,2,function(a,b,c){return pb(a,c)||pb(b,c)});function vb(a,b",
+    "number\"==typeof b||\"number\"==typeof c?a(+b,+c):a(b,c):a(+b,+c)}rb.pr",
+    "ototype.evaluate=function(a){return this.Z.u(this.ga,this.la,a)};rb.pro",
+    "totype.toString=function(){var a=\"Binary Expression: \"+this.Z,a=a+H(t",
+    "his.ga);return a+=H(this.la)};function ub(a,b,c,d){this.xa=a;this.ja=b;",
+    "this.i=c;this.u=d}ub.prototype.toString=function(){return this.xa};var ",
+    "vb={};\nfunction K(a,b,c,d){if(vb.hasOwnProperty(a))throw Error(\"Binar",
+    "y operator already created: \"+a);a=new ub(a,b,c,d);return vb[a.toStrin",
+    "g()]=a}K(\"div\",6,1,function(a,b,c){return I(a,c)/I(b,c)});K(\"mod\",6",
+    ",1,function(a,b,c){return I(a,c)%I(b,c)});K(\"*\",6,1,function(a,b,c){r",
+    "eturn I(a,c)*I(b,c)});K(\"+\",5,1,function(a,b,c){return I(a,c)+I(b,c)}",
+    ");K(\"-\",5,1,function(a,b,c){return I(a,c)-I(b,c)});K(\"<\",4,2,functi",
+    "on(a,b,c){return tb(function(a,b){return a<b},a,b,c)});\nK(\">\",4,2,fu",
+    "nction(a,b,c){return tb(function(a,b){return a>b},a,b,c)});K(\"<=\",4,2",
+    ",function(a,b,c){return tb(function(a,b){return a<=b},a,b,c)});K(\">=\"",
+    ",4,2,function(a,b,c){return tb(function(a,b){return a>=b},a,b,c)});var ",
+    "sb=K(\"=\",3,2,function(a,b,c){return tb(function(a,b){return a==b},a,b",
+    ",c,!0)});K(\"!=\",3,2,function(a,b,c){return tb(function(a,b){return a!",
+    "=b},a,b,c,!0)});K(\"and\",2,2,function(a,b,c){return qb(a,c)&&qb(b,c)})",
+    ";K(\"or\",1,2,function(a,b,c){return qb(a,c)||qb(b,c)});function wb(a,b",
     "){if(b.v()&&4!=a.i)throw Error(\"Primary expression must evaluate to no",
-    "deset if filter has predicate(s).\");G.call(this,a.i);this.ka=a;this.f=",
-    "b;this.A=a.h();this.l=a.l}p(vb,G);vb.prototype.evaluate=function(a){a=t",
-    "his.ka.evaluate(a);return wb(this.f,a)};vb.prototype.toString=function(",
-    "){var a=\"Filter:\"+I(this.ka);return a+=I(this.f)};function xb(a,b){if",
+    "deset if filter has predicate(s).\");F.call(this,a.i);this.ka=a;this.f=",
+    "b;this.A=a.h();this.l=a.l}p(wb,F);wb.prototype.evaluate=function(a){a=t",
+    "his.ka.evaluate(a);return xb(this.f,a)};wb.prototype.toString=function(",
+    "){var a=\"Filter:\"+H(this.ka);return a+=H(this.f)};function yb(a,b){if",
     "(b.length<a.ia)throw Error(\"Function \"+a.m+\" expects at least\"+a.ia",
     "+\" arguments, \"+b.length+\" given\");if(null!==a.Y&&b.length>a.Y)thro",
     "w Error(\"Function \"+a.m+\" expects at most \"+a.Y+\" arguments, \"+b.",
     "length+\" given\");a.va&&q(b,function(b,d){if(4!=b.i)throw Error(\"Argu",
-    "ment \"+d+\" to function \"+a.m+\" is not of type Nodeset: \"+b);});G.c",
-    "all(this,a.i);this.O=a;this.U=b;nb(this,a.A||u(b,function(a){return a.h",
-    "()}));ob(this,a.ta&&!b.length||a.sa&&!!b.length||u(b,function(a){return",
-    " a.l}))}\np(xb,G);xb.prototype.evaluate=function(a){return this.O.u.app",
-    "ly(null,qa(a,this.U))};xb.prototype.toString=function(){var a=\"Functio",
-    "n: \"+this.O;if(this.U.length)var b=r(this.U,function(a,b){return a+I(b",
-    ")},\"Arguments:\"),a=a+I(b);return a};function yb(a,b,c,d,e,f,h,m,y){th",
-    "is.m=a;this.i=b;this.A=c;this.ta=d;this.sa=e;this.u=f;this.ia=h;this.Y=",
-    "k(m)?m:h;this.va=!!y}yb.prototype.toString=function(){return this.m};va",
-    "r zb={};\nfunction N(a,b,c,d,e,f,h,m){if(zb.hasOwnProperty(a))throw Err",
-    "or(\"Function already created: \"+a+\".\");zb[a]=new yb(a,b,c,d,!1,e,f,",
-    "h,m)}N(\"boolean\",2,!1,!1,function(a,b){return pb(b,a)},1);N(\"ceiling",
-    "\",1,!1,!1,function(a,b){return Math.ceil(J(b,a))},1);N(\"concat\",3,!1",
-    ",!1,function(a,b){return r(sa(arguments,1),function(b,d){return b+K(d,a",
-    ")},\"\")},2,null);N(\"contains\",2,!1,!1,function(a,b,c){b=K(b,a);a=K(c",
-    ",a);return-1!=b.indexOf(a)},2);N(\"count\",1,!1,!1,function(a,b){return",
-    " b.evaluate(a).v()},1,1,!0);\nN(\"false\",2,!1,!1,function(){return!1},",
-    "0);N(\"floor\",1,!1,!1,function(a,b){return Math.floor(J(b,a))},1);N(\"",
-    "id\",4,!1,!1,function(a,b){var c=a.s,d=9==c.nodeType?c:c.ownerDocument;",
-    "a=K(b,a).split(/\\s+/);var e=[];q(a,function(a){a=d.getElementById(a);!",
-    "a||0<=oa(e,a)||e.push(a)});e.sort(Ra);var f=new E;q(e,function(a){f.add",
-    "(a)});return f},1);N(\"lang\",2,!1,!1,function(){return!1},1);N(\"last",
-    "\",1,!0,!1,function(a){if(1!=arguments.length)throw Error(\"Function la",
-    "st expects ()\");return a.o},0);\nN(\"local-name\",3,!1,!0,function(a,b",
-    "){return(a=b?kb(b.evaluate(a)):a.s)?a.localName||a.nodeName.toLowerCase",
-    "():\"\"},0,1,!0);N(\"name\",3,!1,!0,function(a,b){return(a=b?kb(b.evalu",
-    "ate(a)):a.s)?a.nodeName.toLowerCase():\"\"},0,1,!0);N(\"namespace-uri\"",
-    ",3,!0,!1,function(){return\"\"},0,1,!0);N(\"normalize-space\",3,!1,!0,f",
-    "unction(a,b){return(b?K(b,a):D(a.s)).replace(/[\\s\\xa0]+/g,\" \").repl",
-    "ace(/^\\s+|\\s+$/g,\"\")},0,1);N(\"not\",2,!1,!1,function(a,b){return!p",
-    "b(b,a)},1);\nN(\"number\",1,!1,!0,function(a,b){return b?J(b,a):+D(a.s)",
-    "},0,1);N(\"position\",1,!0,!1,function(a){return a.ya},0);N(\"round\",1",
-    ",!1,!1,function(a,b){return Math.round(J(b,a))},1);N(\"starts-with\",2,",
-    "!1,!1,function(a,b,c){b=K(b,a);a=K(c,a);return 0==b.lastIndexOf(a,0)},2",
-    ");N(\"string\",3,!1,!0,function(a,b){return b?K(b,a):D(a.s)},0,1);N(\"s",
-    "tring-length\",1,!1,!0,function(a,b){return(b?K(b,a):D(a.s)).length},0,",
-    "1);\nN(\"substring\",3,!1,!1,function(a,b,c,d){c=J(c,a);if(isNaN(c)||In",
-    "finity==c||-Infinity==c)return\"\";d=d?J(d,a):Infinity;if(isNaN(d)||-In",
-    "finity===d)return\"\";c=Math.round(c)-1;var e=Math.max(c,0);a=K(b,a);re",
-    "turn Infinity==d?a.substring(e):a.substring(e,c+Math.round(d))},2,3);N(",
-    "\"substring-after\",3,!1,!1,function(a,b,c){b=K(b,a);a=K(c,a);c=b.index",
-    "Of(a);return-1==c?\"\":b.substring(c+a.length)},2);\nN(\"substring-befo",
-    "re\",3,!1,!1,function(a,b,c){b=K(b,a);a=K(c,a);a=b.indexOf(a);return-1=",
-    "=a?\"\":b.substring(0,a)},2);N(\"sum\",1,!1,!1,function(a,b){a=b.evalua",
-    "te(a).iterator();b=0;for(var c=a.next();c;c=a.next())b+=+D(c);return b}",
-    ",1,1,!0);N(\"translate\",3,!1,!1,function(a,b,c,d){b=K(b,a);c=K(c,a);va",
-    "r e=K(d,a);d={};for(var f=0;f<c.length;f++)a=c.charAt(f),a in d||(d[a]=",
-    "e.charAt(f));c=\"\";for(f=0;f<b.length;f++)a=b.charAt(f),c+=a in d?d[a]",
-    ":a;return c},3);N(\"true\",2,!1,!1,function(){return!0},0);function F(a",
-    ",b){this.na=a;this.ha=k(b)?b:null;this.B=null;switch(a){case \"comment",
-    "\":this.B=8;break;case \"text\":this.B=3;break;case \"processing-instru",
-    "ction\":this.B=7;break;case \"node\":break;default:throw Error(\"Unexpe",
-    "cted argument\");}}function Ab(a){return\"comment\"==a||\"text\"==a||\"",
-    "processing-instruction\"==a||\"node\"==a}F.prototype.matches=function(a",
-    "){return null===this.B||this.B==a.nodeType};F.prototype.getName=functio",
-    "n(){return this.na};\nF.prototype.toString=function(){var a=\"Kind Test",
-    ": \"+this.na;null===this.ha||(a+=I(this.ha));return a};function Bb(a){G",
-    ".call(this,3);this.ma=a.substring(1,a.length-1)}p(Bb,G);Bb.prototype.ev",
-    "aluate=function(){return this.ma};Bb.prototype.toString=function(){retu",
-    "rn\"Literal: \"+this.ma};function Cb(a,b){this.m=a.toLowerCase();a=\"*",
-    "\"==this.m?\"*\":\"http://www.w3.org/1999/xhtml\";this.R=b?b.toLowerCas",
-    "e():a}Cb.prototype.matches=function(a){var b=a.nodeType;if(1!=b&&2!=b)r",
-    "eturn!1;b=k(a.localName)?a.localName:a.nodeName;return\"*\"!=this.m&&th",
-    "is.m!=b.toLowerCase()?!1:\"*\"==this.R?!0:this.R==(a.namespaceURI?a.nam",
-    "espaceURI.toLowerCase():\"http://www.w3.org/1999/xhtml\")};Cb.prototype",
-    ".getName=function(){return this.m};\nCb.prototype.toString=function(){r",
-    "eturn\"Name Test: \"+(\"http://www.w3.org/1999/xhtml\"==this.R?\"\":thi",
-    "s.R+\":\")+this.m};function Db(a){G.call(this,1);this.oa=a}p(Db,G);Db.p",
-    "rototype.evaluate=function(){return this.oa};Db.prototype.toString=func",
-    "tion(){return\"Number: \"+this.oa};function Eb(a,b){G.call(this,a.i);th",
-    "is.ea=a;this.L=b;this.A=a.h();this.l=a.l;1==this.L.length&&(a=this.L[0]",
-    ",a.V||a.C!=Fb||(a=a.T,\"*\"!=a.getName()&&(this.K={name:a.getName(),I:n",
-    "ull})))}p(Eb,G);function Gb(){G.call(this,4)}p(Gb,G);Gb.prototype.evalu",
-    "ate=function(a){var b=new E;a=a.s;9==a.nodeType?b.add(a):b.add(a.ownerD",
-    "ocument);return b};Gb.prototype.toString=function(){return\"Root Helper",
-    " Expression\"};function Hb(){G.call(this,4)}p(Hb,G);Hb.prototype.evalua",
-    "te=function(a){var b=new E;b.add(a.s);return b};\nHb.prototype.toString",
-    "=function(){return\"Context Helper Expression\"};function Ib(a){return",
-    "\"/\"==a||\"//\"==a}\nEb.prototype.evaluate=function(a){var b=this.ea.e",
-    "valuate(a);if(!(b instanceof E))throw Error(\"Filter expression must ev",
+    "ment \"+d+\" to function \"+a.m+\" is not of type Nodeset: \"+b);});F.c",
+    "all(this,a.i);this.O=a;this.U=b;ob(this,a.A||r(b,function(a){return a.h",
+    "()}));pb(this,a.ta&&!b.length||a.sa&&!!b.length||r(b,function(a){return",
+    " a.l}))}\np(yb,F);yb.prototype.evaluate=function(a){return this.O.u.app",
+    "ly(null,ra(a,this.U))};yb.prototype.toString=function(){var a=\"Functio",
+    "n: \"+this.O;if(this.U.length)var b=pa(this.U,function(a,b){return a+H(",
+    "b)},\"Arguments:\"),a=a+H(b);return a};function zb(a,b,c,d,e,f,h,m,y){t",
+    "his.m=a;this.i=b;this.A=c;this.ta=d;this.sa=e;this.u=f;this.ia=h;this.Y",
+    "=k(m)?m:h;this.va=!!y}zb.prototype.toString=function(){return this.m};v",
+    "ar Ab={};\nfunction L(a,b,c,d,e,f,h,m){if(Ab.hasOwnProperty(a))throw Er",
+    "ror(\"Function already created: \"+a+\".\");Ab[a]=new zb(a,b,c,d,!1,e,f",
+    ",h,m)}L(\"boolean\",2,!1,!1,function(a,b){return qb(b,a)},1);L(\"ceilin",
+    "g\",1,!1,!1,function(a,b){return Math.ceil(I(b,a))},1);L(\"concat\",3,!",
+    "1,!1,function(a,b){return pa(ta(arguments,1),function(b,d){return b+J(d",
+    ",a)},\"\")},2,null);L(\"contains\",2,!1,!1,function(a,b,c){b=J(b,a);a=J",
+    "(c,a);return-1!=b.indexOf(a)},2);L(\"count\",1,!1,!1,function(a,b){retu",
+    "rn b.evaluate(a).v()},1,1,!0);\nL(\"false\",2,!1,!1,function(){return!1",
+    "},0);L(\"floor\",1,!1,!1,function(a,b){return Math.floor(I(b,a))},1);L(",
+    "\"id\",4,!1,!1,function(a,b){var c=a.s,d=9==c.nodeType?c:c.ownerDocumen",
+    "t;a=J(b,a).split(/\\s+/);var e=[];q(a,function(a){a=d.getElementById(a)",
+    ";!a||0<=oa(e,a)||e.push(a)});e.sort(Sa);var f=new D;q(e,function(a){f.a",
+    "dd(a)});return f},1);L(\"lang\",2,!1,!1,function(){return!1},1);L(\"las",
+    "t\",1,!0,!1,function(a){if(1!=arguments.length)throw Error(\"Function l",
+    "ast expects ()\");return a.o},0);\nL(\"local-name\",3,!1,!0,function(a,",
+    "b){return(a=b?lb(b.evaluate(a)):a.s)?a.localName||a.nodeName.toLowerCas",
+    "e():\"\"},0,1,!0);L(\"name\",3,!1,!0,function(a,b){return(a=b?lb(b.eval",
+    "uate(a)):a.s)?a.nodeName.toLowerCase():\"\"},0,1,!0);L(\"namespace-uri",
+    "\",3,!0,!1,function(){return\"\"},0,1,!0);L(\"normalize-space\",3,!1,!0",
+    ",function(a,b){return(b?J(b,a):C(a.s)).replace(/[\\s\\xa0]+/g,\" \").re",
+    "place(/^\\s+|\\s+$/g,\"\")},0,1);L(\"not\",2,!1,!1,function(a,b){return",
+    "!qb(b,a)},1);\nL(\"number\",1,!1,!0,function(a,b){return b?I(b,a):+C(a.",
+    "s)},0,1);L(\"position\",1,!0,!1,function(a){return a.ya},0);L(\"round\"",
+    ",1,!1,!1,function(a,b){return Math.round(I(b,a))},1);L(\"starts-with\",",
+    "2,!1,!1,function(a,b,c){b=J(b,a);a=J(c,a);return 0==b.lastIndexOf(a,0)}",
+    ",2);L(\"string\",3,!1,!0,function(a,b){return b?J(b,a):C(a.s)},0,1);L(",
+    "\"string-length\",1,!1,!0,function(a,b){return(b?J(b,a):C(a.s)).length}",
+    ",0,1);\nL(\"substring\",3,!1,!1,function(a,b,c,d){c=I(c,a);if(isNaN(c)|",
+    "|Infinity==c||-Infinity==c)return\"\";d=d?I(d,a):Infinity;if(isNaN(d)||",
+    "-Infinity===d)return\"\";c=Math.round(c)-1;var e=Math.max(c,0);a=J(b,a)",
+    ";return Infinity==d?a.substring(e):a.substring(e,c+Math.round(d))},2,3)",
+    ";L(\"substring-after\",3,!1,!1,function(a,b,c){b=J(b,a);a=J(c,a);c=b.in",
+    "dexOf(a);return-1==c?\"\":b.substring(c+a.length)},2);\nL(\"substring-b",
+    "efore\",3,!1,!1,function(a,b,c){b=J(b,a);a=J(c,a);a=b.indexOf(a);return",
+    "-1==a?\"\":b.substring(0,a)},2);L(\"sum\",1,!1,!1,function(a,b){a=b.eva",
+    "luate(a).iterator();b=0;for(var c=a.next();c;c=a.next())b+=+C(c);return",
+    " b},1,1,!0);L(\"translate\",3,!1,!1,function(a,b,c,d){b=J(b,a);c=J(c,a)",
+    ";var e=J(d,a);d={};for(var f=0;f<c.length;f++)a=c.charAt(f),a in d||(d[",
+    "a]=e.charAt(f));c=\"\";for(f=0;f<b.length;f++)a=b.charAt(f),c+=a in d?d",
+    "[a]:a;return c},3);L(\"true\",2,!1,!1,function(){return!0},0);function ",
+    "E(a,b){this.na=a;this.ha=k(b)?b:null;this.B=null;switch(a){case \"comme",
+    "nt\":this.B=8;break;case \"text\":this.B=3;break;case \"processing-inst",
+    "ruction\":this.B=7;break;case \"node\":break;default:throw Error(\"Unex",
+    "pected argument\");}}function Bb(a){return\"comment\"==a||\"text\"==a||",
+    "\"processing-instruction\"==a||\"node\"==a}E.prototype.matches=function",
+    "(a){return null===this.B||this.B==a.nodeType};E.prototype.getName=funct",
+    "ion(){return this.na};\nE.prototype.toString=function(){var a=\"Kind Te",
+    "st: \"+this.na;null===this.ha||(a+=H(this.ha));return a};function Cb(a)",
+    "{F.call(this,3);this.ma=a.substring(1,a.length-1)}p(Cb,F);Cb.prototype.",
+    "evaluate=function(){return this.ma};Cb.prototype.toString=function(){re",
+    "turn\"Literal: \"+this.ma};function Db(a,b){this.m=a.toLowerCase();a=\"",
+    "*\"==this.m?\"*\":\"http://www.w3.org/1999/xhtml\";this.R=b?b.toLowerCa",
+    "se():a}Db.prototype.matches=function(a){var b=a.nodeType;if(1!=b&&2!=b)",
+    "return!1;b=k(a.localName)?a.localName:a.nodeName;return\"*\"!=this.m&&t",
+    "his.m!=b.toLowerCase()?!1:\"*\"==this.R?!0:this.R==(a.namespaceURI?a.na",
+    "mespaceURI.toLowerCase():\"http://www.w3.org/1999/xhtml\")};Db.prototyp",
+    "e.getName=function(){return this.m};\nDb.prototype.toString=function(){",
+    "return\"Name Test: \"+(\"http://www.w3.org/1999/xhtml\"==this.R?\"\":th",
+    "is.R+\":\")+this.m};function Eb(a){F.call(this,1);this.oa=a}p(Eb,F);Eb.",
+    "prototype.evaluate=function(){return this.oa};Eb.prototype.toString=fun",
+    "ction(){return\"Number: \"+this.oa};function Fb(a,b){F.call(this,a.i);t",
+    "his.ea=a;this.L=b;this.A=a.h();this.l=a.l;1==this.L.length&&(a=this.L[0",
+    "],a.V||a.C!=Gb||(a=a.T,\"*\"!=a.getName()&&(this.K={name:a.getName(),I:",
+    "null})))}p(Fb,F);function Hb(){F.call(this,4)}p(Hb,F);Hb.prototype.eval",
+    "uate=function(a){var b=new D;a=a.s;9==a.nodeType?b.add(a):b.add(a.owner",
+    "Document);return b};Hb.prototype.toString=function(){return\"Root Helpe",
+    "r Expression\"};function Ib(){F.call(this,4)}p(Ib,F);Ib.prototype.evalu",
+    "ate=function(a){var b=new D;b.add(a.s);return b};\nIb.prototype.toStrin",
+    "g=function(){return\"Context Helper Expression\"};function Jb(a){return",
+    "\"/\"==a||\"//\"==a}\nFb.prototype.evaluate=function(a){var b=this.ea.e",
+    "valuate(a);if(!(b instanceof D))throw Error(\"Filter expression must ev",
     "aluate to nodeset.\");a=this.L;for(var c=0,d=a.length;c<d&&b.v();c++){v",
-    "ar e=a[c],f=b.iterator(e.C.H);if(e.h()||e.C!=Jb)if(e.h()||e.C!=Kb){var ",
-    "h=f.next();for(b=e.evaluate(new $a(h));null!=(h=f.next());)h=e.evaluate",
-    "(new $a(h)),b=jb(b,h)}else h=f.next(),b=e.evaluate(new $a(h));else{for(",
+    "ar e=a[c],f=b.iterator(e.C.H);if(e.h()||e.C!=Kb)if(e.h()||e.C!=Lb){var ",
+    "h=f.next();for(b=e.evaluate(new ab(h));null!=(h=f.next());)h=e.evaluate",
+    "(new ab(h)),b=kb(b,h)}else h=f.next(),b=e.evaluate(new ab(h));else{for(",
     "h=f.next();(b=f.next())&&(!h.contains||h.contains(b))&&b.compareDocumen",
-    "tPosition(h)&8;h=b);b=e.evaluate(new $a(h))}}return b};\nEb.prototype.t",
-    "oString=function(){var a=\"Path Expression:\"+I(this.ea);if(this.L.leng",
-    "th){var b=r(this.L,function(a,b){return a+I(b)},\"Steps:\");a+=I(b)}ret",
-    "urn a};function O(a,b){this.f=a;this.H=!!b}function wb(a,b,c){for(c=c||",
-    "0;c<a.f.length;c++)for(var d=a.f[c],e=b.iterator(),f=b.v(),h,m=0;h=e.ne",
-    "xt();m++){var y=a.H?f-m:m+1;h=d.evaluate(new $a(h,y,f));if(\"number\"==",
-    "typeof h)y=y==h;else if(\"string\"==typeof h||\"boolean\"==typeof h)y=!",
-    "!h;else if(h instanceof E)y=0<h.v();else throw Error(\"Predicate.evalua",
-    "te returned an unexpected type.\");y||e.remove()}return b}O.prototype.D",
-    "=function(){return 0<this.f.length?this.f[0].D():null};\nO.prototype.h=",
-    "function(){for(var a=0;a<this.f.length;a++){var b=this.f[a];if(b.h()||1",
-    "==b.i||0==b.i)return!0}return!1};O.prototype.v=function(){return this.f",
-    ".length};O.prototype.toString=function(){return r(this.f,function(a,b){",
-    "return a+I(b)},\"Predicates:\")};function P(a,b,c,d){G.call(this,4);thi",
-    "s.C=a;this.T=b;this.f=c||new O([]);this.V=!!d;b=this.f.D();a.Aa&&b&&(th",
-    "is.K={name:b.name,I:b.I});this.A=this.f.h()}p(P,G);\nP.prototype.evalua",
-    "te=function(a){var b=a.s,c=this.D(),d=null,e=null,f=0;c&&(d=c.name,e=c.",
-    "I?K(c.I,a):null,f=1);if(this.V)if(this.h()||this.C!=Lb)if(b=(new P(Mb,n",
-    "ew F(\"node\"))).evaluate(a).iterator(),c=b.next())for(a=this.u(c,d,e,f",
-    ");null!=(c=b.next());)a=jb(a,this.u(c,d,e,f));else a=new E;else a=fb(th",
-    "is.T,b,d,e),a=wb(this.f,a,f);else a=this.u(a.s,d,e,f);return a};P.proto",
-    "type.u=function(a,b,c,d){a=this.C.O(this.T,a,b,c);return a=wb(this.f,a,",
-    "d)};\nP.prototype.toString=function(){var a=\"Step:\"+I(\"Operator: \"+",
-    "(this.V?\"//\":\"/\"));this.C.m&&(a+=I(\"Axis: \"+this.C));a+=I(this.T)",
-    ";if(this.f.v()){var b=r(this.f.f,function(a,b){return a+I(b)},\"Predica",
-    "tes:\");a+=I(b)}return a};function Nb(a,b,c,d){this.m=a;this.O=b;this.H",
-    "=c;this.Aa=d}Nb.prototype.toString=function(){return this.m};var Ob={};",
-    "function Q(a,b,c,d){if(Ob.hasOwnProperty(a))throw Error(\"Axis already ",
-    "created: \"+a);b=new Nb(a,b,c,!!d);return Ob[a]=b}\nQ(\"ancestor\",func",
-    "tion(a,b){for(var c=new E;b=b.parentNode;)a.matches(b)&&c.unshift(b);re",
-    "turn c},!0);Q(\"ancestor-or-self\",function(a,b){var c=new E;do a.match",
-    "es(b)&&c.unshift(b);while(b=b.parentNode);return c},!0);\nvar Fb=Q(\"at",
-    "tribute\",function(a,b){var c=new E,d=a.getName();if(b=b.attributes)if(",
-    "a instanceof F&&null===a.B||\"*\"==d)for(d=0;a=b[d];d++)c.add(a);else(a",
-    "=b.getNamedItem(d))&&c.add(a);return c},!1),Lb=Q(\"child\",function(a,b",
-    ",c,d,e){c=l(c)?c:null;d=l(d)?d:null;e=e||new E;for(b=b.firstChild;b;b=b",
-    ".nextSibling)eb(b,c,d)&&a.matches(b)&&e.add(b);return e},!1,!0);Q(\"des",
-    "cendant\",fb,!1,!0);\nvar Mb=Q(\"descendant-or-self\",function(a,b,c,d)",
-    "{var e=new E;eb(b,c,d)&&a.matches(b)&&e.add(b);return fb(a,b,c,d,e)},!1",
-    ",!0),Jb=Q(\"following\",function(a,b,c,d){var e=new E;do for(var f=b;f=",
-    "f.nextSibling;)eb(f,c,d)&&a.matches(f)&&e.add(f),e=fb(a,f,c,d,e);while(",
-    "b=b.parentNode);return e},!1,!0);Q(\"following-sibling\",function(a,b){",
-    "for(var c=new E;b=b.nextSibling;)a.matches(b)&&c.add(b);return c},!1);Q",
-    "(\"namespace\",function(){return new E},!1);\nvar Pb=Q(\"parent\",funct",
-    "ion(a,b){var c=new E;if(9==b.nodeType)return c;if(2==b.nodeType)return ",
-    "c.add(b.ownerElement),c;b=b.parentNode;a.matches(b)&&c.add(b);return c}",
-    ",!1),Kb=Q(\"preceding\",function(a,b,c,d){var e=new E,f=[];do f.unshift",
-    "(b);while(b=b.parentNode);for(var h=1,m=f.length;h<m;h++){var y=[];for(",
-    "b=f[h];b=b.previousSibling;)y.unshift(b);for(var H=0,t=y.length;H<t;H++",
-    ")b=y[H],eb(b,c,d)&&a.matches(b)&&e.add(b),e=fb(a,b,c,d,e)}return e},!0,",
-    "!0);\nQ(\"preceding-sibling\",function(a,b){for(var c=new E;b=b.previou",
-    "sSibling;)a.matches(b)&&c.unshift(b);return c},!0);var Qb=Q(\"self\",fu",
-    "nction(a,b){var c=new E;a.matches(b)&&c.add(b);return c},!1);function R",
-    "b(a){G.call(this,1);this.da=a;this.A=a.h();this.l=a.l}p(Rb,G);Rb.protot",
-    "ype.evaluate=function(a){return-J(this.da,a)};Rb.prototype.toString=fun",
-    "ction(){return\"Unary Expression: -\"+I(this.da)};function Sb(a){G.call",
-    "(this,4);this.S=a;nb(this,u(this.S,function(a){return a.h()}));ob(this,",
-    "u(this.S,function(a){return a.l}))}p(Sb,G);Sb.prototype.evaluate=functi",
-    "on(a){var b=new E;q(this.S,function(c){c=c.evaluate(a);if(!(c instanceo",
-    "f E))throw Error(\"Path expression must evaluate to NodeSet.\");b=jb(b,",
-    "c)});return b};Sb.prototype.toString=function(){return r(this.S,functio",
-    "n(a,b){return a+I(b)},\"Union Expression:\")};function Tb(a,b){this.a=a",
-    ";this.wa=b}function Ub(a){for(var b,c=[];;){R(a,\"Missing right hand si",
-    "de of binary expression.\");b=Vb(a);var d=a.a.next();if(!d)break;var e=",
-    "(d=ub[d]||null)&&d.ja;if(!e){a.a.back();break}for(;c.length&&e<=c[c.len",
-    "gth-1].ja;)b=new qb(c.pop(),c.pop(),b);c.push(b,d)}for(;c.length;)b=new",
-    " qb(c.pop(),c.pop(),b);return b}function R(a,b){if(a.a.empty())throw Er",
-    "ror(b);}function Wb(a,b){a=a.a.next();if(a!=b)throw Error(\"Bad token, ",
-    "expected: \"+b+\" got: \"+a);}\nfunction Xb(a){a=a.a.next();if(\")\"!=a",
-    ")throw Error(\"Bad token: \"+a);}function Yb(a){a=a.a.next();if(2>a.len",
-    "gth)throw Error(\"Unclosed literal string\");return new Bb(a)}\nfunctio",
-    "n Zb(a){var b=[];if(Ib(C(a.a))){var c=a.a.next();var d=C(a.a);if(\"/\"=",
-    "=c&&(a.a.empty()||\".\"!=d&&\"..\"!=d&&\"@\"!=d&&\"*\"!=d&&!/(?![0-9])[",
-    "\\w]/.test(d)))return new Gb;d=new Gb;R(a,\"Missing next location step.",
-    "\");c=$b(a,c);b.push(c)}else{a:{c=C(a.a);d=c.charAt(0);switch(d){case ",
-    "\"$\":throw Error(\"Variable reference not allowed in HTML XPath\");cas",
-    "e \"(\":a.a.next();c=Ub(a);R(a,'unclosed \"(\"');Wb(a,\")\");break;case",
-    " '\"':case \"'\":c=Yb(a);break;default:if(isNaN(+c))if(!Ab(c)&&/(?![0-9",
-    "])[\\w]/.test(d)&&\"(\"==C(a.a,\n1)){c=a.a.next();c=zb[c]||null;a.a.nex",
-    "t();for(d=[];\")\"!=C(a.a);){R(a,\"Missing function argument list.\");d",
-    ".push(Ub(a));if(\",\"!=C(a.a))break;a.a.next()}R(a,\"Unclosed function ",
-    "argument list.\");Xb(a);c=new xb(c,d)}else{c=null;break a}else c=new Db",
-    "(+a.a.next())}\"[\"==C(a.a)&&(d=new O(ac(a)),c=new vb(c,d))}if(c)if(Ib(",
-    "C(a.a)))d=c;else return c;else c=$b(a,\"/\"),d=new Hb,b.push(c)}for(;Ib",
-    "(C(a.a));)c=a.a.next(),R(a,\"Missing next location step.\"),c=$b(a,c),b",
-    ".push(c);return new Eb(d,b)}\nfunction $b(a,b){if(\"/\"!=b&&\"//\"!=b)t",
-    "hrow Error('Step op should be \"/\" or \"//\"');if(\".\"==C(a.a)){var c",
-    "=new P(Qb,new F(\"node\"));a.a.next();return c}if(\"..\"==C(a.a))return",
-    " c=new P(Pb,new F(\"node\")),a.a.next(),c;if(\"@\"==C(a.a)){var d=Fb;a.",
-    "a.next();R(a,\"Missing attribute name\")}else if(\"::\"==C(a.a,1)){if(!",
-    "/(?![0-9])[\\w]/.test(C(a.a).charAt(0)))throw Error(\"Bad token: \"+a.a",
-    ".next());var e=a.a.next();d=Ob[e]||null;if(!d)throw Error(\"No axis wit",
-    "h name: \"+e);a.a.next();R(a,\"Missing node name\")}else d=Lb;e=\nC(a.a",
-    ");if(/(?![0-9])[\\w\\*]/.test(e.charAt(0)))if(\"(\"==C(a.a,1)){if(!Ab(e",
-    "))throw Error(\"Invalid node type: \"+e);e=a.a.next();if(!Ab(e))throw E",
-    "rror(\"Invalid type name: \"+e);Wb(a,\"(\");R(a,\"Bad nodetype\");var f",
-    "=C(a.a).charAt(0),h=null;if('\"'==f||\"'\"==f)h=Yb(a);R(a,\"Bad nodetyp",
-    "e\");Xb(a);e=new F(e,h)}else if(e=a.a.next(),f=e.indexOf(\":\"),-1==f)e",
-    "=new Cb(e);else{var h=e.substring(0,f);if(\"*\"==h)var m=\"*\";else if(",
-    "m=a.wa(h),!m)throw Error(\"Namespace prefix not declared: \"+h);e=e.sub",
-    "str(f+1);e=new Cb(e,m)}else throw Error(\"Bad token: \"+\na.a.next());a",
-    "=new O(ac(a),d.H);return c||new P(d,e,a,\"//\"==b)}function ac(a){for(v",
-    "ar b=[];\"[\"==C(a.a);){a.a.next();R(a,\"Missing predicate expression.",
-    "\");var c=Ub(a);b.push(c);R(a,\"Unclosed predicate expression.\");Wb(a,",
-    "\"]\")}return b}function Vb(a){if(\"-\"==C(a.a))return a.a.next(),new R",
-    "b(Vb(a));var b=Zb(a);if(\"|\"!=C(a.a))a=b;else{for(b=[b];\"|\"==a.a.nex",
-    "t();)R(a,\"Missing next union location path.\"),b.push(Zb(a));a.a.back(",
-    ");a=new Sb(b)}return a};function bc(a){switch(a.nodeType){case 1:return",
-    " ja(cc,a);case 9:return bc(a.documentElement);case 11:case 10:case 6:ca",
-    "se 12:return dc;default:return a.parentNode?bc(a.parentNode):dc}}functi",
-    "on dc(){return null}function cc(a,b){if(a.prefix==b)return a.namespaceU",
-    "RI||\"http://www.w3.org/1999/xhtml\";var c=a.getAttributeNode(\"xmlns:",
-    "\"+b);return c&&c.specified?c.value||null:a.parentNode&&9!=a.parentNode",
-    ".nodeType?cc(a.parentNode,b):null};function ec(a,b){if(!a.length)throw ",
-    "Error(\"Empty XPath expression.\");a=bb(a);if(a.empty())throw Error(\"I",
-    "nvalid XPath expression.\");b?ea(b)||(b=ia(b.lookupNamespaceURI,b)):b=f",
-    "unction(){return null};var c=Ub(new Tb(a,b));if(!a.empty())throw Error(",
-    "\"Bad token: \"+a.next());this.evaluate=function(a,b){a=c.evaluate(new ",
-    "$a(a));return new S(a,b)}}\nfunction S(a,b){if(0==b)if(a instanceof E)b",
-    "=4;else if(\"string\"==typeof a)b=2;else if(\"number\"==typeof a)b=1;el",
-    "se if(\"boolean\"==typeof a)b=3;else throw Error(\"Unexpected evaluatio",
-    "n result.\");if(2!=b&&1!=b&&3!=b&&!(a instanceof E))throw Error(\"value",
-    " could not be converted to the specified type\");this.resultType=b;swit",
-    "ch(b){case 2:this.stringValue=a instanceof E?lb(a):\"\"+a;break;case 1:",
-    "this.numberValue=a instanceof E?+lb(a):+a;break;case 3:this.booleanValu",
-    "e=a instanceof E?0<a.v():!!a;break;case 4:case 5:case 6:case 7:var c=\n",
-    "a.iterator();var d=[];for(var e=c.next();e;e=c.next())d.push(e);this.sn",
-    "apshotLength=a.v();this.invalidIteratorState=!1;break;case 8:case 9:thi",
-    "s.singleNodeValue=kb(a);break;default:throw Error(\"Unknown XPathResult",
-    " type.\");}var f=0;this.iterateNext=function(){if(4!=b&&5!=b)throw Erro",
-    "r(\"iterateNext called with wrong result type\");return f>=d.length?nul",
-    "l:d[f++]};this.snapshotItem=function(a){if(6!=b&&7!=b)throw Error(\"sna",
-    "pshotItem called with wrong result type\");return a>=d.length||0>a?null",
-    ":d[a]}}\nS.ANY_TYPE=0;S.NUMBER_TYPE=1;S.STRING_TYPE=2;S.BOOLEAN_TYPE=3;",
-    "S.UNORDERED_NODE_ITERATOR_TYPE=4;S.ORDERED_NODE_ITERATOR_TYPE=5;S.UNORD",
-    "ERED_NODE_SNAPSHOT_TYPE=6;S.ORDERED_NODE_SNAPSHOT_TYPE=7;S.ANY_UNORDERE",
-    "D_NODE_TYPE=8;S.FIRST_ORDERED_NODE_TYPE=9;function fc(a){this.lookupNam",
-    "espaceURI=bc(a)}\nba(\"wgxpath.install\",function(a,b){a=a||aa;var c=a.",
-    "Document&&a.Document.prototype||a.document;if(!c.evaluate||b)a.XPathRes",
-    "ult=S,c.evaluate=function(a,b,c,h){return(new ec(a,c)).evaluate(b,h)},c",
-    ".createExpression=function(a,b){return new ec(a,b)},c.createNSResolver=",
-    "function(a){return new fc(a)}});var U={};U.aa=function(){var a={Ea:\"ht",
-    "tp://www.w3.org/2000/svg\"};return function(b){return a[b]||null}}();\n",
-    "U.u=function(a,b,c){var d=A(a);if(!d.documentElement)return null;try{fo",
-    "r(var e=d.createNSResolver?d.createNSResolver(d.documentElement):U.aa,f",
-    "={},h=d.getElementsByTagName(\"*\"),m=0;m<h.length;++m){var y=h[m],H=y.",
-    "namespaceURI;if(H&&!f[H]){var t=y.lookupPrefix(H);if(!t)var z=H.match(",
-    "\".*/(\\\\w+)/?$\"),t=z?z[1]:\"xhtml\";f[H]=t}}var M={},T;for(T in f)M[",
-    "f[T]]=T;e=function(a){return M[a]||null};try{return d.evaluate(b,a,e,c,",
-    "null)}catch(Da){if(\"TypeError\"===Da.name)return e=d.createNSResolver?",
-    "d.createNSResolver(d.documentElement):\nU.aa,d.evaluate(b,a,e,c,null);t",
-    "hrow Da;}}catch(Da){throw new v(32,\"Unable to locate an element with t",
-    "he xpath expression \"+b+\" because of the following error:\\n\"+Da);}}",
-    ";U.ba=function(a,b){if(!a||1!=a.nodeType)throw new v(32,'The result of ",
-    "the xpath expression \"'+b+'\" is: '+a+\". It should be an element.\");",
-    "};\nU.za=function(a,b){var c=function(){var c=U.u(b,a,9);return c?c.sin",
-    "gleNodeValue||null:b.selectSingleNode?(c=A(b),c.setProperty&&c.setPrope",
-    "rty(\"SelectionLanguage\",\"XPath\"),b.selectSingleNode(a)):null}();nul",
-    "l===c||U.ba(c,a);return c};\nU.Ca=function(a,b){var c=function(){var c=",
-    "U.u(b,a,7);if(c){for(var e=c.snapshotLength,f=[],h=0;h<e;++h)f.push(c.s",
-    "napshotItem(h));return f}return b.selectNodes?(c=A(b),c.setProperty&&c.",
-    "setProperty(\"SelectionLanguage\",\"XPath\"),b.selectNodes(a)):[]}();q(",
-    "c,function(b){U.ba(b,a)});return c};function gc(a,b,c,d){this.top=a;thi",
-    "s.right=b;this.bottom=c;this.left=d}g=gc.prototype;g.clone=function(){r",
-    "eturn new gc(this.top,this.right,this.bottom,this.left)};g.toString=fun",
-    "ction(){return\"(\"+this.top+\"t, \"+this.right+\"r, \"+this.bottom+\"b",
-    ", \"+this.left+\"l)\"};g.contains=function(a){return this&&a?a instance",
-    "of gc?a.left>=this.left&&a.right<=this.right&&a.top>=this.top&&a.bottom",
-    "<=this.bottom:a.x>=this.left&&a.x<=this.right&&a.y>=this.top&&a.y<=this",
-    ".bottom:!1};\ng.expand=function(a,b,c,d){fa(a)?(this.top-=a.top,this.ri",
-    "ght+=a.right,this.bottom+=a.bottom,this.left-=a.left):(this.top-=a,this",
-    ".right+=Number(b),this.bottom+=Number(c),this.left-=Number(d));return t",
-    "his};g.ceil=function(){this.top=Math.ceil(this.top);this.right=Math.cei",
-    "l(this.right);this.bottom=Math.ceil(this.bottom);this.left=Math.ceil(th",
-    "is.left);return this};\ng.floor=function(){this.top=Math.floor(this.top",
-    ");this.right=Math.floor(this.right);this.bottom=Math.floor(this.bottom)",
-    ";this.left=Math.floor(this.left);return this};g.round=function(){this.t",
-    "op=Math.round(this.top);this.right=Math.round(this.right);this.bottom=M",
-    "ath.round(this.bottom);this.left=Math.round(this.left);return this};g.t",
-    "ranslate=function(a,b){a instanceof x?(this.left+=a.x,this.right+=a.x,t",
-    "his.top+=a.y,this.bottom+=a.y):(this.left+=a,this.right+=a,n(b)&&(this.",
-    "top+=b,this.bottom+=b));return this};\ng.scale=function(a,b){b=n(b)?b:a",
-    ";this.left*=a;this.right*=a;this.top*=b;this.bottom*=b;return this};fun",
-    "ction V(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d}g=V.",
-    "prototype;g.clone=function(){return new V(this.left,this.top,this.width",
-    ",this.height)};g.toString=function(){return\"(\"+this.left+\", \"+this.",
-    "top+\" - \"+this.width+\"w x \"+this.height+\"h)\"};g.contains=function",
-    "(a){return a instanceof x?a.x>=this.left&&a.x<=this.left+this.width&&a.",
-    "y>=this.top&&a.y<=this.top+this.height:this.left<=a.left&&this.left+thi",
-    "s.width>=a.left+a.width&&this.top<=a.top&&this.top+this.height>=a.top+a",
-    ".height};\ng.ceil=function(){this.left=Math.ceil(this.left);this.top=Ma",
-    "th.ceil(this.top);this.width=Math.ceil(this.width);this.height=Math.cei",
-    "l(this.height);return this};g.floor=function(){this.left=Math.floor(thi",
-    "s.left);this.top=Math.floor(this.top);this.width=Math.floor(this.width)",
-    ";this.height=Math.floor(this.height);return this};g.round=function(){th",
-    "is.left=Math.round(this.left);this.top=Math.round(this.top);this.width=",
-    "Math.round(this.width);this.height=Math.round(this.height);return this}",
-    ";\ng.translate=function(a,b){a instanceof x?(this.left+=a.x,this.top+=a",
-    ".y):(this.left+=a,n(b)&&(this.top+=b));return this};g.scale=function(a,",
-    "b){b=n(b)?b:a;this.left*=a;this.width*=a;this.top*=b;this.height*=b;ret",
-    "urn this};var hc=\"function\"===typeof ShadowRoot,ic=\"A AREA BUTTON IN",
-    "PUT LABEL SELECT TEXTAREA\".split(\" \");function jc(a){return u(ic,fun",
-    "ction(b){return B(a,b)})||null!=Xa(a)&&0<=Number(a.tabIndex)||(kc(a)||(",
-    "B(a,\"INPUT\")?\"file\"==a.type.toLowerCase():!1))&&!a.readOnly}var lc=",
-    "\"BUTTON INPUT OPTGROUP OPTION SELECT TEXTAREA\".split(\" \");\nfunctio",
-    "n mc(a){return u(lc,function(b){return B(a,b)})?a.disabled?!1:a.parentN",
-    "ode&&1==a.parentNode.nodeType&&B(a,\"OPTGROUP\")||B(a,\"OPTION\")?mc(a.",
-    "parentNode):!Ua(a,function(a){var b=a.parentNode;if(b&&B(b,\"FIELDSET\"",
-    ")&&b.disabled){if(!B(a,\"LEGEND\"))return!0;for(;a=k(a.previousElementS",
-    "ibling)?a.previousElementSibling:Pa(a.previousSibling);)if(B(a,\"LEGEND",
-    "\"))return!0}return!1},!0):!0}var nc=\"text search tel url email passwo",
-    "rd number\".split(\" \");\nfunction kc(a){return B(a,\"TEXTAREA\")?!0:B",
-    "(a,\"INPUT\")?0<=oa(nc,a.type.toLowerCase()):oc(a)?!0:!1}function oc(a)",
-    "{function b(a){return\"inherit\"==a.contentEditable?(a=pc(a))?b(a):!1:",
-    "\"true\"==a.contentEditable}return k(a.contentEditable)?k(a.isContentEd",
-    "itable)?a.isContentEditable:b(a):!1}function pc(a){for(a=a.parentNode;a",
-    "&&1!=a.nodeType&&9!=a.nodeType&&11!=a.nodeType;)a=a.parentNode;return B",
-    "(a)?a:null}\nfunction W(a,b){b=na(b);if(\"float\"==b||\"cssFloat\"==b||",
-    "\"styleFloat\"==b)b=\"cssFloat\";a:{var c=b;var d=A(a);if(d.defaultView",
-    "&&d.defaultView.getComputedStyle&&(d=d.defaultView.getComputedStyle(a,n",
-    "ull))){c=d[c]||d.getPropertyValue(c)||\"\";break a}c=\"\"}a=c||qc(a,b);",
-    "if(null===a)a=null;else if(0<=oa(ua,b)){b:{var e=a.match(xa);if(e&&(b=N",
-    "umber(e[1]),c=Number(e[2]),d=Number(e[3]),e=Number(e[4]),0<=b&&255>=b&&",
-    "0<=c&&255>=c&&0<=d&&255>=d&&0<=e&&1>=e)){b=[b,c,d,e];break b}b=null}if(",
-    "!b)b:{if(d=a.match(ya))if(b=Number(d[1]),\nc=Number(d[2]),d=Number(d[3]",
-    "),0<=b&&255>=b&&0<=c&&255>=c&&0<=d&&255>=d){b=[b,c,d,1];break b}b=null}",
-    "if(!b)b:{b=a.toLowerCase();c=ta[b.toLowerCase()];if(!c&&(c=\"#\"==b.cha",
-    "rAt(0)?b:\"#\"+b,4==c.length&&(c=c.replace(va,\"#$1$1$2$2$3$3\")),!wa.t",
-    "est(c))){b=null;break b}b=[parseInt(c.substr(1,2),16),parseInt(c.substr",
-    "(3,2),16),parseInt(c.substr(5,2),16),1]}a=b?\"rgba(\"+b.join(\", \")+\"",
-    ")\":a}return a}\nfunction qc(a,b){var c=a.currentStyle||a.style,d=c[b];",
-    "!k(d)&&ea(c.getPropertyValue)&&(d=c.getPropertyValue(b));return\"inheri",
-    "t\"!=d?k(d)?d:null:(a=pc(a))?qc(a,b):null}\nfunction rc(a,b,c){function",
-    " d(a){var b=sc(a);return 0<b.height&&0<b.width?!0:B(a,\"PATH\")&&(0<b.h",
-    "eight||0<b.width)?(a=W(a,\"stroke-width\"),!!a&&0<parseInt(a,10)):\"hid",
-    "den\"!=W(a,\"overflow\")&&u(a.childNodes,function(a){return 3==a.nodeTy",
-    "pe||B(a)&&d(a)})}function e(a){return tc(a)==X&&pa(a.childNodes,functio",
-    "n(a){return!B(a)||e(a)||!d(a)})}if(!B(a))throw Error(\"Argument to isSh",
-    "own must be of type Element\");if(B(a,\"BODY\"))return!0;if(B(a,\"OPTIO",
-    "N\")||B(a,\"OPTGROUP\"))return a=Ua(a,function(a){return B(a,\"SELECT\"",
-    ")}),\n!!a&&rc(a,!0,c);var f=uc(a);if(f)return!!f.fa&&0<f.rect.width&&0<",
-    "f.rect.height&&rc(f.fa,b,c);if(B(a,\"INPUT\")&&\"hidden\"==a.type.toLow",
-    "erCase()||B(a,\"NOSCRIPT\"))return!1;f=W(a,\"visibility\");return\"coll",
-    "apse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!=vc(a))&&d(a)?!e(a):!1}\nfunction",
-    " wc(a){var b=hc?function(c){if(\"none\"==W(c,\"display\"))return!1;do{v",
-    "ar d=c.parentNode;if(c.getDestinationInsertionPoints){var e=c.getDestin",
-    "ationInsertionPoints();0<e.length&&(d=e[e.length-1])}if(d instanceof Sh",
-    "adowRoot)return!0;!d||9!=d.nodeType&&11!=d.nodeType||(d=null)}while(a&&",
-    "1!=a.nodeType);return!d||b(d)}:function(a){if(\"none\"==W(a,\"display\"",
-    "))return!1;a=pc(a);return!a||b(a)};return rc(a,!0,b)}var X=\"hidden\";",
-    "\nfunction tc(a){function b(a){function b(a){return a==h?!0:0==W(a,\"di",
-    "splay\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"static\"==W(a,\"",
-    "position\")?!1:!0}var c=W(a,\"position\");if(\"fixed\"==c)return H=!0,a",
-    "==h?null:h;for(a=pc(a);a&&!b(a);)a=pc(a);return a}function c(a){var b=a",
-    ";if(\"visible\"==y)if(a==h&&m)b=m;else if(a==m)return{x:\"visible\",y:",
-    "\"visible\"};b={x:W(b,\"overflow-x\"),y:W(b,\"overflow-y\")};a==h&&(b.x",
-    "=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);retur",
-    "n b}function d(a){if(a==h){var b=(new Wa(f)).M;\na=b.scrollingElement?b",
-    ".scrollingElement:b.body||b.documentElement;b=b.parentWindow||b.default",
-    "View;a=new x(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}el",
-    "se a=new x(a.scrollLeft,a.scrollTop);return a}var e=xc(a);var f=A(a),h=",
-    "f.documentElement,m=f.body,y=W(h,\"overflow\"),H;for(a=b(a);a;a=b(a)){v",
-    "ar t=c(a);if(\"visible\"!=t.x||\"visible\"!=t.y){var z=sc(a);if(0==z.wi",
-    "dth||0==z.height)return X;var M=e.right<z.left,T=e.bottom<z.top;if(M&&",
-    "\"hidden\"==t.x||T&&\"hidden\"==t.y)return X;if(M&&\"visible\"!=t.x||\n",
-    "T&&\"visible\"!=t.y){M=d(a);T=e.bottom<z.top-M.y;if(e.right<z.left-M.x&",
-    "&\"visible\"!=t.x||T&&\"visible\"!=t.x)return X;e=tc(a);return e==X?X:",
-    "\"scroll\"}M=e.left>=z.left+z.width;z=e.top>=z.top+z.height;if(M&&\"hid",
-    "den\"==t.x||z&&\"hidden\"==t.y)return X;if(M&&\"visible\"!=t.x||z&&\"vi",
-    "sible\"!=t.y){if(H&&(t=d(a),e.left>=h.scrollWidth-t.x||e.right>=h.scrol",
-    "lHeight-t.y))return X;e=tc(a);return e==X?X:\"scroll\"}}}return\"none\"",
-    "}\nfunction sc(a){var b=uc(a);if(b)return b.rect;if(B(a,\"HTML\"))retur",
-    "n a=A(a),a=((a?a.parentWindow||a.defaultView:window)||window).document,",
-    "a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=new Ma(a.clie",
-    "ntWidth,a.clientHeight),new V(0,0,a.width,a.height);try{var c=a.getBoun",
-    "dingClientRect()}catch(d){return new V(0,0,0,0)}return new V(c.left,c.t",
-    "op,c.right-c.left,c.bottom-c.top)}\nfunction uc(a){var b=B(a,\"MAP\");i",
-    "f(!b&&!B(a,\"AREA\"))return null;var c=b?a:B(a.parentNode,\"MAP\")?a.pa",
-    "rentNode:null,d=null,e=null;c&&c.name&&(d=U.za('/descendant::*[@usemap ",
-    "= \"#'+c.name+'\"]',A(c)))&&(e=sc(d),b||\"default\"==a.shape.toLowerCas",
-    "e()||(a=yc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.min(Math.ma",
-    "x(a.top,0),e.height),e=new V(b+e.left,c+e.top,Math.min(a.width,e.width-",
-    "b),Math.min(a.height,e.height-c))));return{fa:d,rect:e||new V(0,0,0,0)}",
-    "}\nfunction yc(a){var b=a.shape.toLowerCase();a=a.coords.split(\",\");i",
-    "f(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new V(b,c,a[2]-b,a",
-    "[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new V(a[0]-b,a[1]-b,",
-    "2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;",
-    "f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[",
-    "f+1]),e=Math.max(e,a[f+1]);return new V(b,c,d-b,e-c)}return new V(0,0,0",
-    ",0)}function xc(a){a=sc(a);return new gc(a.top,a.left+a.width,a.top+a.h",
-    "eight,a.left)}\nfunction vc(a){var b=1,c=W(a,\"opacity\");c&&(b=Number(",
-    "c));(a=pc(a))&&(b*=vc(a));return b};function zc(){this.N=ka.document.do",
-    "cumentElement;var a=Va(A(this.N));a&&Ac(this,a)}function Ac(a,b){a.N=b;",
-    "B(b,\"OPTION\")&&Ua(b,function(a){return B(a,\"SELECT\")})}function Bc(",
-    "a){var b=Ua(a.N,function(a){return!!a&&B(a)&&jc(a)},!0),b=b||a.N;a=Va(A",
-    "(b));if(b!=a){if(a&&ea(a.blur)&&!B(a,\"BODY\"))try{a.blur()}catch(c){th",
-    "row c;}ea(b.focus)&&b.focus()}};La();La();function Cc(a,b,c){this.B=a;t",
-    "his.pa=b;this.qa=c}Cc.prototype.create=function(a){a=A(a).createEvent(",
-    "\"HTMLEvents\");a.initEvent(this.B,this.pa,this.qa);return a};Cc.protot",
-    "ype.toString=function(){return this.B};var Dc=new Cc(\"change\",!0,!1);",
-    "function Ec(a,b){this.w={};this.g=[];this.G=0;var c=arguments.length;if",
-    "(1<c){if(c%2)throw Error(\"Uneven number of arguments\");for(var d=0;d<",
-    "c;d+=2)this.set(arguments[d],arguments[d+1])}else a&&this.addAll(a)}fun",
-    "ction Fc(a){Gc(a);return a.g.concat()}g=Ec.prototype;g.clear=function()",
-    "{this.w={};this.G=this.g.length=0};g.remove=function(a){return Object.p",
-    "rototype.hasOwnProperty.call(this.w,a)?(delete this.w[a],this.G--,this.",
-    "g.length>2*this.G&&Gc(this),!0):!1};\nfunction Gc(a){var b,c;if(a.G!=a.",
-    "g.length){for(b=c=0;c<a.g.length;){var d=a.g[c];Object.prototype.hasOwn",
-    "Property.call(a.w,d)&&(a.g[b++]=d);c++}a.g.length=b}if(a.G!=a.g.length)",
-    "{var e={};for(b=c=0;c<a.g.length;)d=a.g[c],Object.prototype.hasOwnPrope",
-    "rty.call(e,d)||(a.g[b++]=d,e[d]=1),c++;a.g.length=b}}g.get=function(a,b",
-    "){return Object.prototype.hasOwnProperty.call(this.w,a)?this.w[a]:b};g.",
-    "set=function(a,b){Object.prototype.hasOwnProperty.call(this.w,a)||(this",
-    ".G++,this.g.push(a));this.w[a]=b};\ng.addAll=function(a){if(a instanceo",
-    "f Ec){var b=Fc(a);Gc(a);for(var c=[],d=0;d<a.g.length;d++)c.push(a.w[a.",
-    "g[d]]);a=c}else{b=[];var d=0;for(e in a)b[d++]=e;d=[];var e=0;for(c in ",
-    "a)d[e++]=a[c];a=d}for(c=0;c<b.length;c++)this.set(b[c],a[c])};g.forEach",
-    "=function(a,b){for(var c=Fc(this),d=0;d<c.length;d++){var e=c[d],f=this",
-    ".get(e);a.call(b,f,e,this)}};g.clone=function(){return new Ec(this)};va",
-    "r Hc={};function Y(a,b,c){fa(a)&&(a=a.b);a=new Ic(a);!b||b in Hc&&!c||(",
-    "Hc[b]={key:a,shift:!1},c&&(Hc[c]={key:a,shift:!0}));return a}function I",
-    "c(a){this.code=a}Y(8);Y(9);Y(13);var Jc=Y(16),Kc=Y(17),Lc=Y(18);Y(19);Y",
-    "(20);Y(27);Y(32,\" \");Y(33);Y(34);Y(35);Y(36);Y(37);Y(38);Y(39);Y(40);",
-    "Y(44);Y(45);Y(46);Y(48,\"0\",\")\");Y(49,\"1\",\"!\");Y(50,\"2\",\"@\")",
-    ";Y(51,\"3\",\"#\");Y(52,\"4\",\"$\");Y(53,\"5\",\"%\");Y(54,\"6\",\"^\"",
-    ");Y(55,\"7\",\"&\");Y(56,\"8\",\"*\");Y(57,\"9\",\"(\");Y(65,\"a\",\"A",
-    "\");Y(66,\"b\",\"B\");Y(67,\"c\",\"C\");Y(68,\"d\",\"D\");\nY(69,\"e\",",
-    "\"E\");Y(70,\"f\",\"F\");Y(71,\"g\",\"G\");Y(72,\"h\",\"H\");Y(73,\"i\"",
-    ",\"I\");Y(74,\"j\",\"J\");Y(75,\"k\",\"K\");Y(76,\"l\",\"L\");Y(77,\"m",
-    "\",\"M\");Y(78,\"n\",\"N\");Y(79,\"o\",\"O\");Y(80,\"p\",\"P\");Y(81,\"",
-    "q\",\"Q\");Y(82,\"r\",\"R\");Y(83,\"s\",\"S\");Y(84,\"t\",\"T\");Y(85,",
-    "\"u\",\"U\");Y(86,\"v\",\"V\");Y(87,\"w\",\"W\");Y(88,\"x\",\"X\");Y(89",
-    ",\"y\",\"Y\");Y(90,\"z\",\"Z\");var Mc=Y(Ha?{c:91,b:91}:Ga?{c:224,b:91}",
-    ":{c:0,b:91});Y(Ha?{c:92,b:92}:Ga?{c:224,b:93}:{c:0,b:92});Y(Ha?{c:93,b:",
-    "93}:Ga?{c:0,b:0}:{c:93,b:null});Y({c:96,b:96},\"0\");Y({c:97,b:97},\"1",
-    "\");\nY({c:98,b:98},\"2\");Y({c:99,b:99},\"3\");Y({c:100,b:100},\"4\");",
-    "Y({c:101,b:101},\"5\");Y({c:102,b:102},\"6\");Y({c:103,b:103},\"7\");Y(",
-    "{c:104,b:104},\"8\");Y({c:105,b:105},\"9\");Y({c:106,b:106},\"*\");Y({c",
-    ":107,b:107},\"+\");Y({c:109,b:109},\"-\");Y({c:110,b:110},\".\");Y({c:1",
-    "11,b:111},\"/\");Y(144);Y(112);Y(113);Y(114);Y(115);Y(116);Y(117);Y(118",
-    ");Y(119);Y(120);Y(121);Y(122);Y(123);Y({c:107,b:187},\"=\",\"+\");Y(108",
-    ",\",\");Y({c:109,b:189},\"-\",\"_\");Y(188,\",\",\"<\");Y(190,\".\",\">",
-    "\");Y(191,\"/\",\"?\");Y(192,\"`\",\"~\");Y(219,\"[\",\"{\");\nY(220,\"",
+    "tPosition(h)&8;h=b);b=e.evaluate(new ab(h))}}return b};\nFb.prototype.t",
+    "oString=function(){var a=\"Path Expression:\"+H(this.ea);if(this.L.leng",
+    "th){var b=pa(this.L,function(a,b){return a+H(b)},\"Steps:\");a+=H(b)}re",
+    "turn a};function N(a,b){this.f=a;this.H=!!b}function xb(a,b,c){for(c=c|",
+    "|0;c<a.f.length;c++)for(var d=a.f[c],e=b.iterator(),f=b.v(),h,m=0;h=e.n",
+    "ext();m++){var y=a.H?f-m:m+1;h=d.evaluate(new ab(h,y,f));if(\"number\"=",
+    "=typeof h)y=y==h;else if(\"string\"==typeof h||\"boolean\"==typeof h)y=",
+    "!!h;else if(h instanceof D)y=0<h.v();else throw Error(\"Predicate.evalu",
+    "ate returned an unexpected type.\");y||e.remove()}return b}N.prototype.",
+    "D=function(){return 0<this.f.length?this.f[0].D():null};\nN.prototype.h",
+    "=function(){for(var a=0;a<this.f.length;a++){var b=this.f[a];if(b.h()||",
+    "1==b.i||0==b.i)return!0}return!1};N.prototype.v=function(){return this.",
+    "f.length};N.prototype.toString=function(){return pa(this.f,function(a,b",
+    "){return a+H(b)},\"Predicates:\")};function O(a,b,c,d){F.call(this,4);t",
+    "his.C=a;this.T=b;this.f=c||new N([]);this.V=!!d;b=this.f.D();a.Aa&&b&&(",
+    "this.K={name:b.name,I:b.I});this.A=this.f.h()}p(O,F);\nO.prototype.eval",
+    "uate=function(a){var b=a.s,c=this.D(),d=null,e=null,f=0;c&&(d=c.name,e=",
+    "c.I?J(c.I,a):null,f=1);if(this.V)if(this.h()||this.C!=Mb)if(b=(new O(Nb",
+    ",new E(\"node\"))).evaluate(a).iterator(),c=b.next())for(a=this.u(c,d,e",
+    ",f);null!=(c=b.next());)a=kb(a,this.u(c,d,e,f));else a=new D;else a=gb(",
+    "this.T,b,d,e),a=xb(this.f,a,f);else a=this.u(a.s,d,e,f);return a};O.pro",
+    "totype.u=function(a,b,c,d){a=this.C.O(this.T,a,b,c);return a=xb(this.f,",
+    "a,d)};\nO.prototype.toString=function(){var a=\"Step:\"+H(\"Operator: ",
+    "\"+(this.V?\"//\":\"/\"));this.C.m&&(a+=H(\"Axis: \"+this.C));a+=H(this",
+    ".T);if(this.f.v()){var b=pa(this.f.f,function(a,b){return a+H(b)},\"Pre",
+    "dicates:\");a+=H(b)}return a};function Ob(a,b,c,d){this.m=a;this.O=b;th",
+    "is.H=c;this.Aa=d}Ob.prototype.toString=function(){return this.m};var Pb",
+    "={};function P(a,b,c,d){if(Pb.hasOwnProperty(a))throw Error(\"Axis alre",
+    "ady created: \"+a);b=new Ob(a,b,c,!!d);return Pb[a]=b}\nP(\"ancestor\",",
+    "function(a,b){for(var c=new D;b=b.parentNode;)a.matches(b)&&c.unshift(b",
+    ");return c},!0);P(\"ancestor-or-self\",function(a,b){var c=new D;do a.m",
+    "atches(b)&&c.unshift(b);while(b=b.parentNode);return c},!0);\nvar Gb=P(",
+    "\"attribute\",function(a,b){var c=new D,d=a.getName();if(b=b.attributes",
+    ")if(a instanceof E&&null===a.B||\"*\"==d)for(d=0;a=b[d];d++)c.add(a);el",
+    "se(a=b.getNamedItem(d))&&c.add(a);return c},!1),Mb=P(\"child\",function",
+    "(a,b,c,d,e){c=l(c)?c:null;d=l(d)?d:null;e=e||new D;for(b=b.firstChild;b",
+    ";b=b.nextSibling)fb(b,c,d)&&a.matches(b)&&e.add(b);return e},!1,!0);P(",
+    "\"descendant\",gb,!1,!0);\nvar Nb=P(\"descendant-or-self\",function(a,b",
+    ",c,d){var e=new D;fb(b,c,d)&&a.matches(b)&&e.add(b);return gb(a,b,c,d,e",
+    ")},!1,!0),Kb=P(\"following\",function(a,b,c,d){var e=new D;do for(var f",
+    "=b;f=f.nextSibling;)fb(f,c,d)&&a.matches(f)&&e.add(f),e=gb(a,f,c,d,e);w",
+    "hile(b=b.parentNode);return e},!1,!0);P(\"following-sibling\",function(",
+    "a,b){for(var c=new D;b=b.nextSibling;)a.matches(b)&&c.add(b);return c},",
+    "!1);P(\"namespace\",function(){return new D},!1);\nvar Qb=P(\"parent\",",
+    "function(a,b){var c=new D;if(9==b.nodeType)return c;if(2==b.nodeType)re",
+    "turn c.add(b.ownerElement),c;b=b.parentNode;a.matches(b)&&c.add(b);retu",
+    "rn c},!1),Lb=P(\"preceding\",function(a,b,c,d){var e=new D,f=[];do f.un",
+    "shift(b);while(b=b.parentNode);for(var h=1,m=f.length;h<m;h++){var y=[]",
+    ";for(b=f[h];b=b.previousSibling;)y.unshift(b);for(var G=0,t=y.length;G<",
+    "t;G++)b=y[G],fb(b,c,d)&&a.matches(b)&&e.add(b),e=gb(a,b,c,d,e)}return e",
+    "},!0,!0);\nP(\"preceding-sibling\",function(a,b){for(var c=new D;b=b.pr",
+    "eviousSibling;)a.matches(b)&&c.unshift(b);return c},!0);var Rb=P(\"self",
+    "\",function(a,b){var c=new D;a.matches(b)&&c.add(b);return c},!1);funct",
+    "ion Sb(a){F.call(this,1);this.da=a;this.A=a.h();this.l=a.l}p(Sb,F);Sb.p",
+    "rototype.evaluate=function(a){return-I(this.da,a)};Sb.prototype.toStrin",
+    "g=function(){return\"Unary Expression: -\"+H(this.da)};function Tb(a){F",
+    ".call(this,4);this.S=a;ob(this,r(this.S,function(a){return a.h()}));pb(",
+    "this,r(this.S,function(a){return a.l}))}p(Tb,F);Tb.prototype.evaluate=f",
+    "unction(a){var b=new D;q(this.S,function(c){c=c.evaluate(a);if(!(c inst",
+    "anceof D))throw Error(\"Path expression must evaluate to NodeSet.\");b=",
+    "kb(b,c)});return b};Tb.prototype.toString=function(){return pa(this.S,f",
+    "unction(a,b){return a+H(b)},\"Union Expression:\")};function Ub(a,b){th",
+    "is.a=a;this.wa=b}function Vb(a){for(var b,c=[];;){Q(a,\"Missing right h",
+    "and side of binary expression.\");b=Wb(a);var d=a.a.next();if(!d)break;",
+    "var e=(d=vb[d]||null)&&d.ja;if(!e){a.a.back();break}for(;c.length&&e<=c",
+    "[c.length-1].ja;)b=new rb(c.pop(),c.pop(),b);c.push(b,d)}for(;c.length;",
+    ")b=new rb(c.pop(),c.pop(),b);return b}function Q(a,b){if(a.a.empty())th",
+    "row Error(b);}function Xb(a,b){a=a.a.next();if(a!=b)throw Error(\"Bad t",
+    "oken, expected: \"+b+\" got: \"+a);}\nfunction Yb(a){a=a.a.next();if(\"",
+    ")\"!=a)throw Error(\"Bad token: \"+a);}function Zb(a){a=a.a.next();if(2",
+    ">a.length)throw Error(\"Unclosed literal string\");return new Cb(a)}\nf",
+    "unction $b(a){var b=[];if(Jb(B(a.a))){var c=a.a.next();var d=B(a.a);if(",
+    "\"/\"==c&&(a.a.empty()||\".\"!=d&&\"..\"!=d&&\"@\"!=d&&\"*\"!=d&&!/(?![",
+    "0-9])[\\w]/.test(d)))return new Hb;d=new Hb;Q(a,\"Missing next location",
+    " step.\");c=ac(a,c);b.push(c)}else{a:{c=B(a.a);d=c.charAt(0);switch(d){",
+    "case \"$\":throw Error(\"Variable reference not allowed in HTML XPath\"",
+    ");case \"(\":a.a.next();c=Vb(a);Q(a,'unclosed \"(\"');Xb(a,\")\");break",
+    ";case '\"':case \"'\":c=Zb(a);break;default:if(isNaN(+c))if(!Bb(c)&&/(?",
+    "![0-9])[\\w]/.test(d)&&\"(\"==B(a.a,\n1)){c=a.a.next();c=Ab[c]||null;a.",
+    "a.next();for(d=[];\")\"!=B(a.a);){Q(a,\"Missing function argument list.",
+    "\");d.push(Vb(a));if(\",\"!=B(a.a))break;a.a.next()}Q(a,\"Unclosed func",
+    "tion argument list.\");Yb(a);c=new yb(c,d)}else{c=null;break a}else c=n",
+    "ew Eb(+a.a.next())}\"[\"==B(a.a)&&(d=new N(bc(a)),c=new wb(c,d))}if(c)i",
+    "f(Jb(B(a.a)))d=c;else return c;else c=ac(a,\"/\"),d=new Ib,b.push(c)}fo",
+    "r(;Jb(B(a.a));)c=a.a.next(),Q(a,\"Missing next location step.\"),c=ac(a",
+    ",c),b.push(c);return new Fb(d,b)}\nfunction ac(a,b){if(\"/\"!=b&&\"//\"",
+    "!=b)throw Error('Step op should be \"/\" or \"//\"');if(\".\"==B(a.a)){",
+    "var c=new O(Rb,new E(\"node\"));a.a.next();return c}if(\"..\"==B(a.a))r",
+    "eturn c=new O(Qb,new E(\"node\")),a.a.next(),c;if(\"@\"==B(a.a)){var d=",
+    "Gb;a.a.next();Q(a,\"Missing attribute name\")}else if(\"::\"==B(a.a,1))",
+    "{if(!/(?![0-9])[\\w]/.test(B(a.a).charAt(0)))throw Error(\"Bad token: ",
+    "\"+a.a.next());var e=a.a.next();d=Pb[e]||null;if(!d)throw Error(\"No ax",
+    "is with name: \"+e);a.a.next();Q(a,\"Missing node name\")}else d=Mb;e=",
+    "\nB(a.a);if(/(?![0-9])[\\w\\*]/.test(e.charAt(0)))if(\"(\"==B(a.a,1)){i",
+    "f(!Bb(e))throw Error(\"Invalid node type: \"+e);e=a.a.next();if(!Bb(e))",
+    "throw Error(\"Invalid type name: \"+e);Xb(a,\"(\");Q(a,\"Bad nodetype\"",
+    ");var f=B(a.a).charAt(0),h=null;if('\"'==f||\"'\"==f)h=Zb(a);Q(a,\"Bad ",
+    "nodetype\");Yb(a);e=new E(e,h)}else if(e=a.a.next(),f=e.indexOf(\":\"),",
+    "-1==f)e=new Db(e);else{var h=e.substring(0,f);if(\"*\"==h)var m=\"*\";e",
+    "lse if(m=a.wa(h),!m)throw Error(\"Namespace prefix not declared: \"+h);",
+    "e=e.substr(f+1);e=new Db(e,m)}else throw Error(\"Bad token: \"+\na.a.ne",
+    "xt());a=new N(bc(a),d.H);return c||new O(d,e,a,\"//\"==b)}function bc(a",
+    "){for(var b=[];\"[\"==B(a.a);){a.a.next();Q(a,\"Missing predicate expre",
+    "ssion.\");var c=Vb(a);b.push(c);Q(a,\"Unclosed predicate expression.\")",
+    ";Xb(a,\"]\")}return b}function Wb(a){if(\"-\"==B(a.a))return a.a.next()",
+    ",new Sb(Wb(a));var b=$b(a);if(\"|\"!=B(a.a))a=b;else{for(b=[b];\"|\"==a",
+    ".a.next();)Q(a,\"Missing next union location path.\"),b.push($b(a));a.a",
+    ".back();a=new Tb(b)}return a};function cc(a){switch(a.nodeType){case 1:",
+    "return ja(dc,a);case 9:return cc(a.documentElement);case 11:case 10:cas",
+    "e 6:case 12:return ec;default:return a.parentNode?cc(a.parentNode):ec}}",
+    "function ec(){return null}function dc(a,b){if(a.prefix==b)return a.name",
+    "spaceURI||\"http://www.w3.org/1999/xhtml\";var c=a.getAttributeNode(\"x",
+    "mlns:\"+b);return c&&c.specified?c.value||null:a.parentNode&&9!=a.paren",
+    "tNode.nodeType?dc(a.parentNode,b):null};function fc(a,b){if(!a.length)t",
+    "hrow Error(\"Empty XPath expression.\");a=cb(a);if(a.empty())throw Erro",
+    "r(\"Invalid XPath expression.\");b?ea(b)||(b=ia(b.lookupNamespaceURI,b)",
+    "):b=function(){return null};var c=Vb(new Ub(a,b));if(!a.empty())throw E",
+    "rror(\"Bad token: \"+a.next());this.evaluate=function(a,b){a=c.evaluate",
+    "(new ab(a));return new R(a,b)}}\nfunction R(a,b){if(0==b)if(a instanceo",
+    "f D)b=4;else if(\"string\"==typeof a)b=2;else if(\"number\"==typeof a)b",
+    "=1;else if(\"boolean\"==typeof a)b=3;else throw Error(\"Unexpected eval",
+    "uation result.\");if(2!=b&&1!=b&&3!=b&&!(a instanceof D))throw Error(\"",
+    "value could not be converted to the specified type\");this.resultType=b",
+    ";switch(b){case 2:this.stringValue=a instanceof D?mb(a):\"\"+a;break;ca",
+    "se 1:this.numberValue=a instanceof D?+mb(a):+a;break;case 3:this.boolea",
+    "nValue=a instanceof D?0<a.v():!!a;break;case 4:case 5:case 6:case 7:var",
+    " c=\na.iterator();var d=[];for(var e=c.next();e;e=c.next())d.push(e);th",
+    "is.snapshotLength=a.v();this.invalidIteratorState=!1;break;case 8:case ",
+    "9:this.singleNodeValue=lb(a);break;default:throw Error(\"Unknown XPathR",
+    "esult type.\");}var f=0;this.iterateNext=function(){if(4!=b&&5!=b)throw",
+    " Error(\"iterateNext called with wrong result type\");return f>=d.lengt",
+    "h?null:d[f++]};this.snapshotItem=function(a){if(6!=b&&7!=b)throw Error(",
+    "\"snapshotItem called with wrong result type\");return a>=d.length||0>a",
+    "?null:d[a]}}\nR.ANY_TYPE=0;R.NUMBER_TYPE=1;R.STRING_TYPE=2;R.BOOLEAN_TY",
+    "PE=3;R.UNORDERED_NODE_ITERATOR_TYPE=4;R.ORDERED_NODE_ITERATOR_TYPE=5;R.",
+    "UNORDERED_NODE_SNAPSHOT_TYPE=6;R.ORDERED_NODE_SNAPSHOT_TYPE=7;R.ANY_UNO",
+    "RDERED_NODE_TYPE=8;R.FIRST_ORDERED_NODE_TYPE=9;function gc(a){this.look",
+    "upNamespaceURI=cc(a)}\nba(\"wgxpath.install\",function(a,b){a=a||aa;var",
+    " c=a.Document&&a.Document.prototype||a.document;if(!c.evaluate||b)a.XPa",
+    "thResult=R,c.evaluate=function(a,b,c,h){return(new fc(a,c)).evaluate(b,",
+    "h)},c.createExpression=function(a,b){return new fc(a,b)},c.createNSReso",
+    "lver=function(a){return new gc(a)}});var S={};S.aa=function(){var a={Ea",
+    ":\"http://www.w3.org/2000/svg\"};return function(b){return a[b]||null}}",
+    "();\nS.u=function(a,b,c){var d=x(a);if(!d.documentElement)return null;t",
+    "ry{for(var e=d.createNSResolver?d.createNSResolver(d.documentElement):S",
+    ".aa,f={},h=d.getElementsByTagName(\"*\"),m=0;m<h.length;++m){var y=h[m]",
+    ",G=y.namespaceURI;if(G&&!f[G]){var t=y.lookupPrefix(G);if(!t)var z=G.ma",
+    "tch(\".*/(\\\\w+)/?$\"),t=z?z[1]:\"xhtml\";f[G]=t}}var M={},T;for(T in ",
+    "f)M[f[T]]=T;e=function(a){return M[a]||null};try{return d.evaluate(b,a,",
+    "e,c,null)}catch(Ea){if(\"TypeError\"===Ea.name)return e=d.createNSResol",
+    "ver?d.createNSResolver(d.documentElement):\nS.aa,d.evaluate(b,a,e,c,nul",
+    "l);throw Ea;}}catch(Ea){throw new u(32,\"Unable to locate an element wi",
+    "th the xpath expression \"+b+\" because of the following error:\\n\"+Ea",
+    ");}};S.ba=function(a,b){if(!a||1!=a.nodeType)throw new u(32,'The result",
+    " of the xpath expression \"'+b+'\" is: '+a+\". It should be an element.",
+    "\");};\nS.za=function(a,b){var c=function(){var c=S.u(b,a,9);return c?c",
+    ".singleNodeValue||null:b.selectSingleNode?(c=x(b),c.setProperty&&c.setP",
+    "roperty(\"SelectionLanguage\",\"XPath\"),b.selectSingleNode(a)):null}()",
+    ";null===c||S.ba(c,a);return c};\nS.Ca=function(a,b){var c=function(){va",
+    "r c=S.u(b,a,7);if(c){for(var e=c.snapshotLength,f=[],h=0;h<e;++h)f.push",
+    "(c.snapshotItem(h));return f}return b.selectNodes?(c=x(b),c.setProperty",
+    "&&c.setProperty(\"SelectionLanguage\",\"XPath\"),b.selectNodes(a)):[]}(",
+    ");q(c,function(b){S.ba(b,a)});return c};function hc(a,b,c,d){this.top=a",
+    ";this.right=b;this.bottom=c;this.left=d}g=hc.prototype;g.clone=function",
+    "(){return new hc(this.top,this.right,this.bottom,this.left)};g.toString",
+    "=function(){return\"(\"+this.top+\"t, \"+this.right+\"r, \"+this.bottom",
+    "+\"b, \"+this.left+\"l)\"};g.contains=function(a){return this&&a?a inst",
+    "anceof hc?a.left>=this.left&&a.right<=this.right&&a.top>=this.top&&a.bo",
+    "ttom<=this.bottom:a.x>=this.left&&a.x<=this.right&&a.y>=this.top&&a.y<=",
+    "this.bottom:!1};\ng.expand=function(a,b,c,d){fa(a)?(this.top-=a.top,thi",
+    "s.right+=a.right,this.bottom+=a.bottom,this.left-=a.left):(this.top-=a,",
+    "this.right+=Number(b),this.bottom+=Number(c),this.left-=Number(d));retu",
+    "rn this};g.ceil=function(){this.top=Math.ceil(this.top);this.right=Math",
+    ".ceil(this.right);this.bottom=Math.ceil(this.bottom);this.left=Math.cei",
+    "l(this.left);return this};\ng.floor=function(){this.top=Math.floor(this",
+    ".top);this.right=Math.floor(this.right);this.bottom=Math.floor(this.bot",
+    "tom);this.left=Math.floor(this.left);return this};g.round=function(){th",
+    "is.top=Math.round(this.top);this.right=Math.round(this.right);this.bott",
+    "om=Math.round(this.bottom);this.left=Math.round(this.left);return this}",
+    ";g.translate=function(a,b){a instanceof w?(this.left+=a.x,this.right+=a",
+    ".x,this.top+=a.y,this.bottom+=a.y):(this.left+=a,this.right+=a,n(b)&&(t",
+    "his.top+=b,this.bottom+=b));return this};\ng.scale=function(a,b){b=n(b)",
+    "?b:a;this.left*=a;this.right*=a;this.top*=b;this.bottom*=b;return this}",
+    ";function U(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d}",
+    "g=U.prototype;g.clone=function(){return new U(this.left,this.top,this.w",
+    "idth,this.height)};g.toString=function(){return\"(\"+this.left+\", \"+t",
+    "his.top+\" - \"+this.width+\"w x \"+this.height+\"h)\"};g.contains=func",
+    "tion(a){return a instanceof w?a.x>=this.left&&a.x<=this.left+this.width",
+    "&&a.y>=this.top&&a.y<=this.top+this.height:this.left<=a.left&&this.left",
+    "+this.width>=a.left+a.width&&this.top<=a.top&&this.top+this.height>=a.t",
+    "op+a.height};\ng.ceil=function(){this.left=Math.ceil(this.left);this.to",
+    "p=Math.ceil(this.top);this.width=Math.ceil(this.width);this.height=Math",
+    ".ceil(this.height);return this};g.floor=function(){this.left=Math.floor",
+    "(this.left);this.top=Math.floor(this.top);this.width=Math.floor(this.wi",
+    "dth);this.height=Math.floor(this.height);return this};g.round=function(",
+    "){this.left=Math.round(this.left);this.top=Math.round(this.top);this.wi",
+    "dth=Math.round(this.width);this.height=Math.round(this.height);return t",
+    "his};\ng.translate=function(a,b){a instanceof w?(this.left+=a.x,this.to",
+    "p+=a.y):(this.left+=a,n(b)&&(this.top+=b));return this};g.scale=functio",
+    "n(a,b){b=n(b)?b:a;this.left*=a;this.width*=a;this.top*=b;this.height*=b",
+    ";return this};var ic=\"function\"===typeof ShadowRoot,jc=\"A AREA BUTTO",
+    "N INPUT LABEL SELECT TEXTAREA\".split(\" \");function kc(a){return r(jc",
+    ",function(b){return A(a,b)})||null!=Ya(a)&&0<=Number(a.tabIndex)||lc(a)",
+    "}var mc=\"BUTTON INPUT OPTGROUP OPTION SELECT TEXTAREA\".split(\" \");",
+    "\nfunction nc(a){return r(mc,function(b){return A(a,b)})?a.disabled?!1:",
+    "a.parentNode&&1==a.parentNode.nodeType&&A(a,\"OPTGROUP\")||A(a,\"OPTION",
+    "\")?nc(a.parentNode):!Va(a,function(a){var b=a.parentNode;if(b&&A(b,\"F",
+    "IELDSET\")&&b.disabled){if(!A(a,\"LEGEND\"))return!0;for(;a=k(a.previou",
+    "sElementSibling)?a.previousElementSibling:Qa(a.previousSibling);)if(A(a",
+    ",\"LEGEND\"))return!0}return!1},!0):!0}var oc=\"text search tel url ema",
+    "il password number\".split(\" \");\nfunction V(a,b){return A(a,\"INPUT",
+    "\")?a.type.toLowerCase()==b:!1}function pc(a){function b(a){return\"inh",
+    "erit\"==a.contentEditable?(a=qc(a))?b(a):!1:\"true\"==a.contentEditable",
+    "}return k(a.contentEditable)?k(a.isContentEditable)?a.isContentEditable",
+    ":b(a):!1}\nfunction lc(a){return((A(a,\"TEXTAREA\")?!0:A(a,\"INPUT\")?0",
+    "<=oa(oc,a.type.toLowerCase()):pc(a)?!0:!1)||(A(a,\"INPUT\")?\"file\"==a",
+    ".type.toLowerCase():!1)||V(a,\"range\")||V(a,\"date\")||V(a,\"month\")|",
+    "|V(a,\"week\")||V(a,\"time\")||V(a,\"datetime-local\")||V(a,\"color\"))",
+    "&&!a.readOnly}function qc(a){for(a=a.parentNode;a&&1!=a.nodeType&&9!=a.",
+    "nodeType&&11!=a.nodeType;)a=a.parentNode;return A(a)?a:null}\nfunction ",
+    "W(a,b){b=na(b);if(\"float\"==b||\"cssFloat\"==b||\"styleFloat\"==b)b=\"",
+    "cssFloat\";a:{var c=b;var d=x(a);if(d.defaultView&&d.defaultView.getCom",
+    "putedStyle&&(d=d.defaultView.getComputedStyle(a,null))){c=d[c]||d.getPr",
+    "opertyValue(c)||\"\";break a}c=\"\"}a=c||rc(a,b);if(null===a)a=null;els",
+    "e if(0<=oa(va,b)){b:{var e=a.match(ya);if(e&&(b=Number(e[1]),c=Number(e",
+    "[2]),d=Number(e[3]),e=Number(e[4]),0<=b&&255>=b&&0<=c&&255>=c&&0<=d&&25",
+    "5>=d&&0<=e&&1>=e)){b=[b,c,d,e];break b}b=null}if(!b)b:{if(d=a.match(za)",
+    ")if(b=Number(d[1]),\nc=Number(d[2]),d=Number(d[3]),0<=b&&255>=b&&0<=c&&",
+    "255>=c&&0<=d&&255>=d){b=[b,c,d,1];break b}b=null}if(!b)b:{b=a.toLowerCa",
+    "se();c=ua[b.toLowerCase()];if(!c&&(c=\"#\"==b.charAt(0)?b:\"#\"+b,4==c.",
+    "length&&(c=c.replace(wa,\"#$1$1$2$2$3$3\")),!xa.test(c))){b=null;break ",
+    "b}b=[parseInt(c.substr(1,2),16),parseInt(c.substr(3,2),16),parseInt(c.s",
+    "ubstr(5,2),16),1]}a=b?\"rgba(\"+b.join(\", \")+\")\":a}return a}\nfunct",
+    "ion rc(a,b){var c=a.currentStyle||a.style,d=c[b];!k(d)&&ea(c.getPropert",
+    "yValue)&&(d=c.getPropertyValue(b));return\"inherit\"!=d?k(d)?d:null:(a=",
+    "qc(a))?rc(a,b):null}\nfunction sc(a,b,c){function d(a){var b=tc(a);retu",
+    "rn 0<b.height&&0<b.width?!0:A(a,\"PATH\")&&(0<b.height||0<b.width)?(a=W",
+    "(a,\"stroke-width\"),!!a&&0<parseInt(a,10)):\"hidden\"!=W(a,\"overflow",
+    "\")&&r(a.childNodes,function(a){return 3==a.nodeType||A(a)&&d(a)})}func",
+    "tion e(a){return uc(a)==X&&qa(a.childNodes,function(a){return!A(a)||e(a",
+    ")||!d(a)})}if(!A(a))throw Error(\"Argument to isShown must be of type E",
+    "lement\");if(A(a,\"BODY\"))return!0;if(A(a,\"OPTION\")||A(a,\"OPTGROUP",
+    "\"))return a=Va(a,function(a){return A(a,\"SELECT\")}),\n!!a&&sc(a,!0,c",
+    ");var f=vc(a);if(f)return!!f.fa&&0<f.rect.width&&0<f.rect.height&&sc(f.",
+    "fa,b,c);if(A(a,\"INPUT\")&&\"hidden\"==a.type.toLowerCase()||A(a,\"NOSC",
+    "RIPT\"))return!1;f=W(a,\"visibility\");return\"collapse\"!=f&&\"hidden",
+    "\"!=f&&c(a)&&(b||0!=wc(a))&&d(a)?!e(a):!1}\nfunction xc(a){function b(a",
+    "){if(A(a)&&\"none\"==W(a,\"display\"))return!1;var c;(c=a.parentNode)&&",
+    "c.shadowRoot&&void 0!==a.assignedSlot?c=a.assignedSlot?a.assignedSlot.p",
+    "arentNode:null:a.getDestinationInsertionPoints&&(a=a.getDestinationInse",
+    "rtionPoints(),0<a.length&&(c=a[a.length-1]));return ic&&c instanceof Sh",
+    "adowRoot||c&&(9==c.nodeType||11==c.nodeType)?!0:!!c&&b(c)}return sc(a,!",
+    "0,b)}var X=\"hidden\";\nfunction uc(a){function b(a){function b(a){retu",
+    "rn a==h?!0:0==W(a,\"display\").lastIndexOf(\"inline\",0)||\"absolute\"=",
+    "=c&&\"static\"==W(a,\"position\")?!1:!0}var c=W(a,\"position\");if(\"fi",
+    "xed\"==c)return G=!0,a==h?null:h;for(a=qc(a);a&&!b(a);)a=qc(a);return a",
+    "}function c(a){var b=a;if(\"visible\"==y)if(a==h&&m)b=m;else if(a==m)re",
+    "turn{x:\"visible\",y:\"visible\"};b={x:W(b,\"overflow-x\"),y:W(b,\"over",
+    "flow-y\")};a==h&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.",
+    "y?\"auto\":b.y);return b}function d(a){if(a==h){var b=(new Xa(f)).M;\na",
+    "=b.scrollingElement?b.scrollingElement:b.body||b.documentElement;b=b.pa",
+    "rentWindow||b.defaultView;a=new w(b.pageXOffset||a.scrollLeft,b.pageYOf",
+    "fset||a.scrollTop)}else a=new w(a.scrollLeft,a.scrollTop);return a}var ",
+    "e=yc(a);var f=x(a),h=f.documentElement,m=f.body,y=W(h,\"overflow\"),G;f",
+    "or(a=b(a);a;a=b(a)){var t=c(a);if(\"visible\"!=t.x||\"visible\"!=t.y){v",
+    "ar z=tc(a);if(0==z.width||0==z.height)return X;var M=e.right<z.left,T=e",
+    ".bottom<z.top;if(M&&\"hidden\"==t.x||T&&\"hidden\"==t.y)return X;if(M&&",
+    "\"visible\"!=t.x||\nT&&\"visible\"!=t.y){M=d(a);T=e.bottom<z.top-M.y;if",
+    "(e.right<z.left-M.x&&\"visible\"!=t.x||T&&\"visible\"!=t.x)return X;e=u",
+    "c(a);return e==X?X:\"scroll\"}M=e.left>=z.left+z.width;z=e.top>=z.top+z",
+    ".height;if(M&&\"hidden\"==t.x||z&&\"hidden\"==t.y)return X;if(M&&\"visi",
+    "ble\"!=t.x||z&&\"visible\"!=t.y){if(G&&(t=d(a),e.left>=h.scrollWidth-t.",
+    "x||e.right>=h.scrollHeight-t.y))return X;e=uc(a);return e==X?X:\"scroll",
+    "\"}}}return\"none\"}\nfunction tc(a){var b=vc(a);if(b)return b.rect;if(",
+    "A(a,\"HTML\"))return a=x(a),a=((a?a.parentWindow||a.defaultView:window)",
+    "||window).document,a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.b",
+    "ody,a=new Na(a.clientWidth,a.clientHeight),new U(0,0,a.width,a.height);",
+    "try{var c=a.getBoundingClientRect()}catch(d){return new U(0,0,0,0)}retu",
+    "rn new U(c.left,c.top,c.right-c.left,c.bottom-c.top)}\nfunction vc(a){v",
+    "ar b=A(a,\"MAP\");if(!b&&!A(a,\"AREA\"))return null;var c=b?a:A(a.paren",
+    "tNode,\"MAP\")?a.parentNode:null,d=null,e=null;c&&c.name&&(d=S.za('/des",
+    "cendant::*[@usemap = \"#'+c.name+'\"]',x(c)))&&(e=tc(d),b||\"default\"=",
+    "=a.shape.toLowerCase()||(a=zc(a),b=Math.min(Math.max(a.left,0),e.width)",
+    ",c=Math.min(Math.max(a.top,0),e.height),e=new U(b+e.left,c+e.top,Math.m",
+    "in(a.width,e.width-b),Math.min(a.height,e.height-c))));return{fa:d,rect",
+    ":e||new U(0,0,0,0)}}\nfunction zc(a){var b=a.shape.toLowerCase();a=a.co",
+    "ords.split(\",\");if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return",
+    " new U(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],n",
+    "ew U(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],",
+    "c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[",
+    "f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new U(b,c,d-b,e-c)",
+    "}return new U(0,0,0,0)}function yc(a){a=tc(a);return new hc(a.top,a.lef",
+    "t+a.width,a.top+a.height,a.left)}\nfunction wc(a){var b=1,c=W(a,\"opaci",
+    "ty\");c&&(b=Number(c));(a=qc(a))&&(b*=wc(a));return b};function Ac(){th",
+    "is.N=ka.document.documentElement;var a=Wa(x(this.N));a&&Bc(this,a)}func",
+    "tion Bc(a,b){a.N=b;A(b,\"OPTION\")&&Va(b,function(a){return A(a,\"SELEC",
+    "T\")})}function Cc(a){var b=Va(a.N,function(a){return!!a&&A(a)&&kc(a)},",
+    "!0),b=b||a.N;a=Wa(x(b));if(b!=a){if(a&&ea(a.blur)&&!A(a,\"BODY\"))try{a",
+    ".blur()}catch(c){throw c;}ea(b.focus)&&b.focus()}};Ma();Ma();function D",
+    "c(a,b,c){this.B=a;this.pa=b;this.qa=c}Dc.prototype.create=function(a){a",
+    "=x(a).createEvent(\"HTMLEvents\");a.initEvent(this.B,this.pa,this.qa);r",
+    "eturn a};Dc.prototype.toString=function(){return this.B};var Ec=new Dc(",
+    "\"blur\",!1,!1),Fc=new Dc(\"change\",!0,!1);function Gc(a,b){b=b.create",
+    "(a,void 0);\"isTrusted\"in b||(b.isTrusted=!1);a.dispatchEvent(b)};func",
+    "tion Hc(a,b){this.w={};this.g=[];this.G=0;var c=arguments.length;if(1<c",
+    "){if(c%2)throw Error(\"Uneven number of arguments\");for(var d=0;d<c;d+",
+    "=2)this.set(arguments[d],arguments[d+1])}else a&&this.addAll(a)}functio",
+    "n Ic(a){Jc(a);return a.g.concat()}g=Hc.prototype;g.clear=function(){thi",
+    "s.w={};this.G=this.g.length=0};g.remove=function(a){return Object.proto",
+    "type.hasOwnProperty.call(this.w,a)?(delete this.w[a],this.G--,this.g.le",
+    "ngth>2*this.G&&Jc(this),!0):!1};\nfunction Jc(a){var b,c;if(a.G!=a.g.le",
+    "ngth){for(b=c=0;c<a.g.length;){var d=a.g[c];Object.prototype.hasOwnProp",
+    "erty.call(a.w,d)&&(a.g[b++]=d);c++}a.g.length=b}if(a.G!=a.g.length){var",
+    " e={};for(b=c=0;c<a.g.length;)d=a.g[c],Object.prototype.hasOwnProperty.",
+    "call(e,d)||(a.g[b++]=d,e[d]=1),c++;a.g.length=b}}g.get=function(a,b){re",
+    "turn Object.prototype.hasOwnProperty.call(this.w,a)?this.w[a]:b};g.set=",
+    "function(a,b){Object.prototype.hasOwnProperty.call(this.w,a)||(this.G++",
+    ",this.g.push(a));this.w[a]=b};\ng.addAll=function(a){if(a instanceof Hc",
+    "){var b=Ic(a);Jc(a);for(var c=[],d=0;d<a.g.length;d++)c.push(a.w[a.g[d]",
+    "]);a=c}else{b=[];var d=0;for(e in a)b[d++]=e;d=[];var e=0;for(c in a)d[",
+    "e++]=a[c];a=d}for(c=0;c<b.length;c++)this.set(b[c],a[c])};g.forEach=fun",
+    "ction(a,b){for(var c=Ic(this),d=0;d<c.length;d++){var e=c[d],f=this.get",
+    "(e);a.call(b,f,e,this)}};g.clone=function(){return new Hc(this)};var Kc",
+    "={};function Y(a,b,c){fa(a)&&(a=a.b);a=new Lc(a);!b||b in Kc&&!c||(Kc[b",
+    "]={key:a,shift:!1},c&&(Kc[c]={key:a,shift:!0}));return a}function Lc(a)",
+    "{this.code=a}Y(8);Y(9);Y(13);var Mc=Y(16),Nc=Y(17),Oc=Y(18);Y(19);Y(20)",
+    ";Y(27);Y(32,\" \");Y(33);Y(34);Y(35);Y(36);Y(37);Y(38);Y(39);Y(40);Y(44",
+    ");Y(45);Y(46);Y(48,\"0\",\")\");Y(49,\"1\",\"!\");Y(50,\"2\",\"@\");Y(5",
+    "1,\"3\",\"#\");Y(52,\"4\",\"$\");Y(53,\"5\",\"%\");Y(54,\"6\",\"^\");Y(",
+    "55,\"7\",\"&\");Y(56,\"8\",\"*\");Y(57,\"9\",\"(\");Y(65,\"a\",\"A\");Y",
+    "(66,\"b\",\"B\");Y(67,\"c\",\"C\");Y(68,\"d\",\"D\");\nY(69,\"e\",\"E\"",
+    ");Y(70,\"f\",\"F\");Y(71,\"g\",\"G\");Y(72,\"h\",\"H\");Y(73,\"i\",\"I",
+    "\");Y(74,\"j\",\"J\");Y(75,\"k\",\"K\");Y(76,\"l\",\"L\");Y(77,\"m\",\"",
+    "M\");Y(78,\"n\",\"N\");Y(79,\"o\",\"O\");Y(80,\"p\",\"P\");Y(81,\"q\",",
+    "\"Q\");Y(82,\"r\",\"R\");Y(83,\"s\",\"S\");Y(84,\"t\",\"T\");Y(85,\"u\"",
+    ",\"U\");Y(86,\"v\",\"V\");Y(87,\"w\",\"W\");Y(88,\"x\",\"X\");Y(89,\"y",
+    "\",\"Y\");Y(90,\"z\",\"Z\");var Pc=Y(Ia?{c:91,b:91}:Ha?{c:224,b:91}:{c:",
+    "0,b:91});Y(Ia?{c:92,b:92}:Ha?{c:224,b:93}:{c:0,b:92});Y(Ia?{c:93,b:93}:",
+    "Ha?{c:0,b:0}:{c:93,b:null});Y({c:96,b:96},\"0\");Y({c:97,b:97},\"1\");",
+    "\nY({c:98,b:98},\"2\");Y({c:99,b:99},\"3\");Y({c:100,b:100},\"4\");Y({c",
+    ":101,b:101},\"5\");Y({c:102,b:102},\"6\");Y({c:103,b:103},\"7\");Y({c:1",
+    "04,b:104},\"8\");Y({c:105,b:105},\"9\");Y({c:106,b:106},\"*\");Y({c:107",
+    ",b:107},\"+\");Y({c:109,b:109},\"-\");Y({c:110,b:110},\".\");Y({c:111,b",
+    ":111},\"/\");Y(144);Y(112);Y(113);Y(114);Y(115);Y(116);Y(117);Y(118);Y(",
+    "119);Y(120);Y(121);Y(122);Y(123);Y({c:107,b:187},\"=\",\"+\");Y(108,\",",
+    "\");Y({c:109,b:189},\"-\",\"_\");Y(188,\",\",\"<\");Y(190,\".\",\">\");",
+    "Y(191,\"/\",\"?\");Y(192,\"`\",\"~\");Y(219,\"[\",\"{\");\nY(220,\"",
     "\\\\\",\"|\");Y(221,\"]\",\"}\");Y({c:59,b:186},\";\",\":\");Y(222,\"'",
-    "\",'\"');var Nc=new Ec;Nc.set(1,Jc);Nc.set(2,Kc);Nc.set(4,Lc);Nc.set(8,",
-    "Mc);(function(a){var b=new Ec;q(Fc(a),function(c){b.set(a.get(c).code,c",
-    ")});return b})(Nc);function Z(){zc.call(this)}p(Z,zc);Z.W=void 0;Z.ra=f",
-    "unction(){return Z.W?Z.W:Z.W=new Z};ba(\"_\",function(a){if(!wc(a)||!mc",
-    "(a)||\"none\"==W(a,\"pointer-events\"))throw new v(12,\"Element is not ",
-    "currently interactable and may not be manipulated\");if(!(kc(a)||B(a,\"",
-    "INPUT\")&&\"file\"==a.type.toLowerCase())||a.readOnly)throw new v(12,\"",
-    "Element must be user-editable in order to clear it.\");var b=Z.ra();Ac(",
-    "b,a);Bc(b);a.value?(a.value=\"\",b=Dc.create(a,void 0),\"isTrusted\"in ",
-    "b||(b.isTrusted=!1),a.dispatchEvent(b)):B(a,\"INPUT\")&&a.getAttribute(",
-    "\"type\")&&\"number\"==a.getAttribute(\"type\").toLowerCase()&&(a.value",
-    "=\n\"\");oc(a)&&(a.innerHTML=\" \")});; return this._.apply(null,argume",
-    "nts);}.apply({navigator:typeof window!='undefined'?window.navigator:nul",
-    "l,document:typeof window!='undefined'?window.document:null}, arguments)",
-    ";}",
+    "\",'\"');var Qc=new Hc;Qc.set(1,Mc);Qc.set(2,Nc);Qc.set(4,Oc);Qc.set(8,",
+    "Pc);(function(a){var b=new Hc;q(Ic(a),function(c){b.set(a.get(c).code,c",
+    ")});return b})(Qc);function Z(){Ac.call(this)}p(Z,Ac);Z.W=void 0;Z.ra=f",
+    "unction(){return Z.W?Z.W:Z.W=new Z};function Rc(a){var b=Z.ra();Bc(b,a)",
+    ";Cc(b)};ba(\"_\",function(a){if(!xc(a)||!nc(a)||\"none\"==W(a,\"pointer",
+    "-events\"))throw new u(12,\"Element is not currently interactable and m",
+    "ay not be manipulated\");if(!lc(a))throw new u(12,\"Element must be use",
+    "r-editable in order to clear it.\");if(a.value){Rc(a);a.value=\"\";Gc(a",
+    ",Fc);Gc(a,Ec);var b=ka.document.body;if(b)Rc(b);else throw new u(13,\"C",
+    "annot unfocus element after clearing.\");}else A(a,\"INPUT\")&&a.getAtt",
+    "ribute(\"type\")&&\"number\"==a.getAttribute(\"type\").toLowerCase()&&(",
+    "Rc(a),a.value=\"\");pc(a)&&(Rc(a),a.innerHTML=\n\" \")});; return this.",
+    "_.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?w",
+    "indow.navigator:null,document:typeof window!='undefined'?window.documen",
+    "t:null}, arguments);}",
     NULL
 };
 
@@ -788,10 +792,10 @@
     ")}}function p(a,b){function c(){}c.prototype=b.prototype;a.Na=b.prototy",
     "pe;a.prototype=new c;a.prototype.constructor=a;a.La=function(a,c,f){for",
     "(var d=Array(arguments.length-2),e=2;e<arguments.length;e++)d[e-2]=argu",
-    "ments[e];return b.prototype[c].apply(a,d)}};var ka=window;var ma=String",
+    "ments[e];return b.prototype[c].apply(a,d)}};var ka=window;var la=String",
     ".prototype.trim?function(a){return a.trim()}:function(a){return a.repla",
-    "ce(/^[\\s\\xa0]+|[\\s\\xa0]+$/g,\"\")};\nfunction na(a,b){var c=0;a=ma(",
-    "String(a)).split(\".\");b=ma(String(b)).split(\".\");for(var d=Math.max",
+    "ce(/^[\\s\\xa0]+|[\\s\\xa0]+$/g,\"\")};\nfunction na(a,b){var c=0;a=la(",
+    "String(a)).split(\".\");b=la(String(b)).split(\".\");for(var d=Math.max",
     "(a.length,b.length),e=0;0==c&&e<d;e++){var f=a[e]||\"\",h=b[e]||\"\";do",
     "{f=/(\\d*)(\\D*)(.*)/.exec(f)||[\"\",\"\",\"\",\"\"];h=/(\\d*)(\\D*)(.*",
     ")/.exec(h)||[\"\",\"\",\"\",\"\"];if(0==f[0].length&&0==h[0].length)bre",
@@ -1290,11 +1294,11 @@
     "ByTagName(\"*\"),l=0;l<h.length;++l){var q=h[l],y=q.namespaceURI;if(y&&",
     "!f[y]){var r=q.lookupPrefix(y);if(!r)var v=y.match(\".*/(\\\\w+)/?$\"),",
     "r=v?v[1]:\"xhtml\";f[y]=r}}var J={},U;for(U in f)J[f[U]]=U;e=function(a",
-    "){return J[a]||null};try{return d.evaluate(b,a,e,c,null)}catch(la){if(",
-    "\"TypeError\"===la.name)return e=d.createNSResolver?d.createNSResolver(",
-    "d.documentElement):\nR.ka,d.evaluate(b,a,e,c,null);throw la;}}catch(la)",
+    "){return J[a]||null};try{return d.evaluate(b,a,e,c,null)}catch(ma){if(",
+    "\"TypeError\"===ma.name)return e=d.createNSResolver?d.createNSResolver(",
+    "d.documentElement):\nR.ka,d.evaluate(b,a,e,c,null);throw ma;}}catch(ma)",
     "{throw new u(32,\"Unable to locate an element with the xpath expression",
-    " \"+b+\" because of the following error:\\n\"+la);}};R.na=function(a,b)",
+    " \"+b+\" because of the following error:\\n\"+ma);}};R.na=function(a,b)",
     "{if(!a||1!=a.nodeType)throw new u(32,'The result of the xpath expressio",
     "n \"'+b+'\" is: '+a+\". It should be an element.\");};\nR.Ja=function(a",
     ",b){var c=function(){var c=R.w(b,a,9);return c?c.singleNodeValue||null:",
@@ -1350,249 +1354,251 @@
     "w Ra(a.right-a.left,a.bottom-a.top)}return new Ra(b,c)};var sc=\"functi",
     "on\"===typeof ShadowRoot;function tc(a){return uc(a)&&vc(a)&&\"none\"!=",
     "T(a,\"pointer-events\")}var wc=\"A AREA BUTTON INPUT LABEL SELECT TEXTA",
-    "REA\".split(\" \");function xc(a){return sa(wc,function(b){return B(a,b",
-    ")})||null!=cb(a)&&0<=Number(a.tabIndex)||((B(a,\"TEXTAREA\")?!0:B(a,\"I",
-    "NPUT\")?0<=qa(yc,a.type.toLowerCase()):zc(a)?!0:!1)||(B(a,\"INPUT\")?\"",
-    "file\"==a.type.toLowerCase():!1))&&!a.readOnly}var Ac=\"BUTTON INPUT OP",
-    "TGROUP OPTION SELECT TEXTAREA\".split(\" \");\nfunction vc(a){return sa",
-    "(Ac,function(b){return B(a,b)})?a.disabled?!1:a.parentNode&&1==a.parent",
-    "Node.nodeType&&B(a,\"OPTGROUP\")||B(a,\"OPTION\")?vc(a.parentNode):!$a(",
-    "a,function(a){var b=a.parentNode;if(b&&B(b,\"FIELDSET\")&&b.disabled){i",
-    "f(!B(a,\"LEGEND\"))return!0;for(;a=k(a.previousElementSibling)?a.previo",
-    "usElementSibling:Va(a.previousSibling);)if(B(a,\"LEGEND\"))return!0}ret",
-    "urn!1},!0):!0}var yc=\"text search tel url email password number\".spli",
-    "t(\" \");\nfunction zc(a){function b(a){return\"inherit\"==a.contentEdi",
-    "table?(a=Bc(a))?b(a):!1:\"true\"==a.contentEditable}return k(a.contentE",
-    "ditable)?k(a.isContentEditable)?a.isContentEditable:b(a):!1}function Bc",
-    "(a){for(a=a.parentNode;a&&1!=a.nodeType&&9!=a.nodeType&&11!=a.nodeType;",
-    ")a=a.parentNode;return B(a)?a:null}\nfunction T(a,b){b=pa(b);if(\"float",
-    "\"==b||\"cssFloat\"==b||\"styleFloat\"==b)b=\"cssFloat\";a=qc(a,b)||Cc(",
-    "a,b);if(null===a)a=null;else if(0<=qa(ya,b)){b:{var c=a.match(Ba);if(c)",
-    "{b=Number(c[1]);var d=Number(c[2]),e=Number(c[3]),c=Number(c[4]);if(0<=",
-    "b&&255>=b&&0<=d&&255>=d&&0<=e&&255>=e&&0<=c&&1>=c){b=[b,d,e,c];break b}",
-    "}b=null}if(!b)b:{if(e=a.match(Ca))if(b=Number(e[1]),d=Number(e[2]),e=Nu",
-    "mber(e[3]),0<=b&&255>=b&&0<=d&&255>=d&&0<=e&&255>=e){b=[b,d,e,1];break ",
-    "b}b=null}if(!b)b:{b=a.toLowerCase();d=xa[b.toLowerCase()];\nif(!d&&(d=",
-    "\"#\"==b.charAt(0)?b:\"#\"+b,4==d.length&&(d=d.replace(za,\"#$1$1$2$2$3",
-    "$3\")),!Aa.test(d))){b=null;break b}b=[parseInt(d.substr(1,2),16),parse",
-    "Int(d.substr(3,2),16),parseInt(d.substr(5,2),16),1]}a=b?\"rgba(\"+b.joi",
-    "n(\", \")+\")\":a}return a}function Cc(a,b){var c=a.currentStyle||a.sty",
-    "le,d=c[b];!k(d)&&ea(c.getPropertyValue)&&(d=c.getPropertyValue(b));retu",
-    "rn\"inherit\"!=d?k(d)?d:null:(a=Bc(a))?Cc(a,b):null}\nfunction Dc(a,b,c",
-    "){function d(a){var b=Ec(a);return 0<b.height&&0<b.width?!0:B(a,\"PATH",
-    "\")&&(0<b.height||0<b.width)?(a=T(a,\"stroke-width\"),!!a&&0<parseInt(a",
-    ",10)):\"hidden\"!=T(a,\"overflow\")&&sa(a.childNodes,function(a){return",
-    " 3==a.nodeType||B(a)&&d(a)})}function e(a){return Fc(a)==V&&ta(a.childN",
-    "odes,function(a){return!B(a)||e(a)||!d(a)})}if(!B(a))throw Error(\"Argu",
-    "ment to isShown must be of type Element\");if(B(a,\"BODY\"))return!0;if",
-    "(B(a,\"OPTION\")||B(a,\"OPTGROUP\"))return a=$a(a,function(a){return B(",
-    "a,\"SELECT\")}),\n!!a&&Dc(a,!0,c);var f=Gc(a);if(f)return!!f.sa&&0<f.re",
-    "ct.width&&0<f.rect.height&&Dc(f.sa,b,c);if(B(a,\"INPUT\")&&\"hidden\"==",
-    "a.type.toLowerCase()||B(a,\"NOSCRIPT\"))return!1;f=T(a,\"visibility\");",
-    "return\"collapse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!=Hc(a))&&d(a)?!e(a):!",
-    "1}\nfunction uc(a){var b=sc?function(c){if(\"none\"==T(c,\"display\"))r",
-    "eturn!1;do{var d=c.parentNode;if(c.getDestinationInsertionPoints){var e",
-    "=c.getDestinationInsertionPoints();0<e.length&&(d=e[e.length-1])}if(d i",
-    "nstanceof ShadowRoot)return!0;!d||9!=d.nodeType&&11!=d.nodeType||(d=nul",
-    "l)}while(a&&1!=a.nodeType);return!d||b(d)}:function(a){if(\"none\"==T(a",
-    ",\"display\"))return!1;a=Bc(a);return!a||b(a)};return Dc(a,!0,b)}var V=",
-    "\"hidden\";\nfunction Fc(a,b){function c(a){function b(a){return a==h?!",
-    "0:0==T(a,\"display\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"sta",
-    "tic\"==T(a,\"position\")?!1:!0}var c=T(a,\"position\");if(\"fixed\"==c)",
-    "return y=!0,a==h?null:h;for(a=Bc(a);a&&!b(a);)a=Bc(a);return a}function",
-    " d(a){var b=a;if(\"visible\"==q)if(a==h&&l)b=l;else if(a==l)return{x:\"",
-    "visible\",y:\"visible\"};b={x:T(b,\"overflow-x\"),y:T(b,\"overflow-y\")",
-    "};a==h&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto",
-    "\":b.y);return b}function e(a){if(a==h){var b=(new bb(f)).R;\na=b.scrol",
-    "lingElement?b.scrollingElement:b.body||b.documentElement;b=b.parentWind",
-    "ow||b.defaultView;a=new z(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.",
-    "scrollTop)}else a=new z(a.scrollLeft,a.scrollTop);return a}b=Ic(a,b);va",
-    "r f=A(a),h=f.documentElement,l=f.body,q=T(h,\"overflow\"),y;for(a=c(a);",
-    "a;a=c(a)){var r=d(a);if(\"visible\"!=r.x||\"visible\"!=r.y){var v=Ec(a)",
-    ";if(0==v.width||0==v.height)return V;var J=b.right<v.left,U=b.bottom<v.",
-    "top;if(J&&\"hidden\"==r.x||U&&\"hidden\"==r.y)return V;if(J&&\"visible",
-    "\"!=r.x||\nU&&\"visible\"!=r.y){J=e(a);U=b.bottom<v.top-J.y;if(b.right<",
-    "v.left-J.x&&\"visible\"!=r.x||U&&\"visible\"!=r.x)return V;b=Fc(a);retu",
-    "rn b==V?V:\"scroll\"}J=b.left>=v.left+v.width;v=b.top>=v.top+v.height;i",
-    "f(J&&\"hidden\"==r.x||v&&\"hidden\"==r.y)return V;if(J&&\"visible\"!=r.",
-    "x||v&&\"visible\"!=r.y){if(y&&(r=e(a),b.left>=h.scrollWidth-r.x||b.righ",
-    "t>=h.scrollHeight-r.y))return V;b=Fc(a);return b==V?V:\"scroll\"}}}retu",
-    "rn\"none\"}\nfunction Ec(a){var b=Gc(a);if(b)return b.rect;if(B(a,\"HTM",
-    "L\"))return a=A(a),a=(Sa(a)||window).document,a=\"CSS1Compat\"==a.compa",
-    "tMode?a.documentElement:a.body,a=new Ra(a.clientWidth,a.clientHeight),n",
-    "ew S(0,0,a.width,a.height);try{var c=a.getBoundingClientRect()}catch(d)",
-    "{return new S(0,0,0,0)}return new S(c.left,c.top,c.right-c.left,c.botto",
-    "m-c.top)}\nfunction Gc(a){var b=B(a,\"MAP\");if(!b&&!B(a,\"AREA\"))retu",
-    "rn null;var c=b?a:B(a.parentNode,\"MAP\")?a.parentNode:null,d=null,e=nu",
-    "ll;c&&c.name&&(d=R.Ja('/descendant::*[@usemap = \"#'+c.name+'\"]',A(c))",
-    ")&&(e=Ec(d),b||\"default\"==a.shape.toLowerCase()||(a=Jc(a),b=Math.min(",
-    "Math.max(a.left,0),e.width),c=Math.min(Math.max(a.top,0),e.height),e=ne",
-    "w S(b+e.left,c+e.top,Math.min(a.width,e.width-b),Math.min(a.height,e.he",
-    "ight-c))));return{sa:d,rect:e||new S(0,0,0,0)}}\nfunction Jc(a){var b=a",
-    ".shape.toLowerCase();a=a.coords.split(\",\");if(\"rect\"==b&&4==a.lengt",
-    "h){var b=a[0],c=a[1];return new S(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b&&",
-    "3==a.length)return b=a[2],new S(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&",
-    "2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.",
-    "min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+1]",
-    ");return new S(b,c,d-b,e-c)}return new S(0,0,0,0)}\nfunction Ic(a,b){a=",
-    "Ec(a);a=new pc(a.top,a.left+a.width,a.top+a.height,a.left);b&&(b=b inst",
-    "anceof S?b:new S(b.x,b.y,1,1),a.left=Math.min(Math.max(a.left+b.left,a.",
-    "left),a.right),a.top=Math.min(Math.max(a.top+b.top,a.top),a.bottom),a.r",
-    "ight=Math.min(Math.max(a.left+b.width,a.left),a.right),a.bottom=Math.mi",
-    "n(Math.max(a.top+b.height,a.top),a.bottom));return a}function Hc(a){var",
-    " b=1,c=T(a,\"opacity\");c&&(b=Number(c));(a=Bc(a))&&(b*=Hc(a));return b",
-    "};function Kc(a,b){this.g=ka.document.documentElement;this.G=null;var c",
-    "=ab(A(this.g));c&&Lc(this,c);this.$=a||new Mc;this.pa=b||new Nc}Kc.prot",
-    "otype.I=function(){return this.g};function Lc(a,b){a.g=b;a.G=B(b,\"OPTI",
-    "ON\")?$a(b,function(a){return B(a,\"SELECT\")}):null}\nKc.prototype.W=f",
-    "unction(a,b,c,d,e,f,h,l){if(!f&&!tc(this.g))return!1;if(d&&Oc!=a&&Pc!=a",
-    ")throw new u(12,\"Event type does not allow related target: \"+a);b={cl",
-    "ientX:b.x,clientY:b.y,button:c,altKey:0!=(this.$.ca&4),ctrlKey:0!=(this",
-    ".$.ca&2),shiftKey:0!=(this.$.ca&1),metaKey:0!=(this.$.ca&8),wheelDelta:",
-    "e||0,relatedTarget:d||null,count:l||1};h=h||1;c=this.g;a!=Qc&&a!=Rc&&h ",
-    "in Sc?c=Sc[h]:this.G&&(c=Tc(this,a));return c?this.pa.W(c,a,b):!0};\nKc",
-    ".prototype.S=function(a,b,c,d,e,f,h,l){if(!l&&!tc(this.g))return!1;if(h",
-    "&&Uc!=a&&Vc!=a)throw new u(12,\"Event type does not allow related targe",
-    "t: \"+a);b={clientX:b.x,clientY:b.y,button:c,altKey:!1,ctrlKey:!1,shift",
-    "Key:!1,metaKey:!1,relatedTarget:h||null,width:0,height:0,pressure:0,rot",
-    "ation:0,pointerId:d,tiltX:0,tiltY:0,pointerType:e,isPrimary:f};c=this.G",
-    "?Tc(this,a):this.g;Sc[d]&&(c=Sc[d]);d=Sa(A(this.g));if(d&&a==Wc){var q=",
-    "d.Element.prototype.msSetPointerCapture;d.Element.prototype.msSetPointe",
-    "rCapture=\nfunction(a){Sc[a]=this}}a=c?this.pa.S(c,a,b):!0;q&&(d.Elemen",
-    "t.prototype.msSetPointerCapture=q);return a};function Tc(a,b){switch(b)",
-    "{case Qc:case Xc:return a.G.multiple?a.g:a.G;default:return a.G.multipl",
-    "e?a.g:null}}function Yc(a){var b=$a(a.g,function(a){return!!a&&B(a)&&xc",
-    "(a)},!0),b=b||a.g;a=ab(A(b));if(b!=a){if(a&&ea(a.blur)&&!B(a,\"BODY\"))",
-    "try{a.blur()}catch(c){throw c;}ea(b.focus)&&b.focus()}}function Mc(){th",
-    "is.ca=0}var Sc={};function Nc(){}Nc.prototype.W=function(a,b,c){return ",
-    "Zc(a,b,c)};\nNc.prototype.S=function(a,b,c){return Zc(a,b,c)};Na();Na()",
-    ";function $c(a,b,c){this.B=a;this.la=b;this.ma=c}$c.prototype.create=fu",
-    "nction(a){a=A(a).createEvent(\"HTMLEvents\");a.initEvent(this.B,this.la",
-    ",this.ma);return a};$c.prototype.toString=function(){return this.B};fun",
-    "ction W(a,b,c){$c.call(this,a,b,c)}p(W,$c);\nW.prototype.create=functio",
-    "n(a,b){if(this==ad)throw new u(9,\"Browser does not support a mouse pix",
-    "el scroll event.\");var c=A(a);a=Sa(c);c=c.createEvent(\"MouseEvents\")",
-    ";this==bd&&(c.wheelDelta=b.wheelDelta);c.initMouseEvent(this.B,this.la,",
-    "this.ma,a,1,b.clientX,b.clientY,b.clientX,b.clientY,b.ctrlKey,b.altKey,",
-    "b.shiftKey,b.metaKey,b.button,b.relatedTarget);return c};function X(a,b",
-    ",c){$c.call(this,a,b,c)}p(X,$c);X.prototype.create=function(){throw new",
-    " u(9,\"Browser does not support MSPointer events.\");};\nvar cd=new $c(",
-    "\"change\",!0,!1),Qc=new W(\"click\",!0,!0),dd=new W(\"contextmenu\",!0",
-    ",!0),ed=new W(\"dblclick\",!0,!0),Rc=new W(\"mousedown\",!0,!0),fd=new ",
-    "W(\"mousemove\",!0,!1),Pc=new W(\"mouseout\",!0,!0),Oc=new W(\"mouseove",
-    "r\",!0,!0),Xc=new W(\"mouseup\",!0,!0),bd=new W(\"mousewheel\",!0,!0),a",
-    "d=new W(\"MozMousePixelScroll\",!0,!0),gd=new X(\"MSGotPointerCapture\"",
-    ",!0,!1),hd=new X(\"MSLostPointerCapture\",!0,!1),Wc=new X(\"MSPointerDo",
-    "wn\",!0,!0),id=new X(\"MSPointerMove\",!0,!0),Uc=new X(\"MSPointerOver",
-    "\",!0,!0),Vc=new X(\"MSPointerOut\",\n!0,!0),jd=new X(\"MSPointerUp\",!",
-    "0,!0);function Zc(a,b,c){b=b.create(a,c);\"isTrusted\"in b||(b.isTruste",
-    "d=!1);return a.dispatchEvent(b)};function kd(a,b){this.D={};this.h=[];t",
-    "his.M=0;var c=arguments.length;if(1<c){if(c%2)throw Error(\"Uneven numb",
-    "er of arguments\");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments",
-    "[d+1])}else a&&this.addAll(a)}function ld(a){md(a);return a.h.concat()}",
-    "g=kd.prototype;g.clear=function(){this.D={};this.M=this.h.length=0};g.r",
-    "emove=function(a){return Object.prototype.hasOwnProperty.call(this.D,a)",
-    "?(delete this.D[a],this.M--,this.h.length>2*this.M&&md(this),!0):!1};\n",
-    "function md(a){var b,c;if(a.M!=a.h.length){for(b=c=0;c<a.h.length;){var",
-    " d=a.h[c];Object.prototype.hasOwnProperty.call(a.D,d)&&(a.h[b++]=d);c++",
-    "}a.h.length=b}if(a.M!=a.h.length){var e={};for(b=c=0;c<a.h.length;)d=a.",
-    "h[c],Object.prototype.hasOwnProperty.call(e,d)||(a.h[b++]=d,e[d]=1),c++",
-    ";a.h.length=b}}g.get=function(a,b){return Object.prototype.hasOwnProper",
-    "ty.call(this.D,a)?this.D[a]:b};g.set=function(a,b){Object.prototype.has",
-    "OwnProperty.call(this.D,a)||(this.M++,this.h.push(a));this.D[a]=b};\ng.",
-    "addAll=function(a){if(a instanceof kd){var b=ld(a);md(a);for(var c=[],d",
-    "=0;d<a.h.length;d++)c.push(a.D[a.h[d]]);a=c}else{b=[];var d=0;for(e in ",
-    "a)b[d++]=e;d=[];var e=0;for(c in a)d[e++]=a[c];a=d}for(c=0;c<b.length;c",
-    "++)this.set(b[c],a[c])};g.forEach=function(a,b){for(var c=ld(this),d=0;",
-    "d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,f,e,this)}};g.clone=f",
-    "unction(){return new kd(this)};var nd={};function Y(a,b,c){fa(a)&&(a=a.",
-    "b);a=new od(a);!b||b in nd&&!c||(nd[b]={key:a,shift:!1},c&&(nd[c]={key:",
-    "a,shift:!0}));return a}function od(a){this.code=a}Y(8);Y(9);Y(13);var p",
-    "d=Y(16),qd=Y(17),rd=Y(18);Y(19);Y(20);Y(27);Y(32,\" \");Y(33);Y(34);Y(3",
-    "5);Y(36);Y(37);Y(38);Y(39);Y(40);Y(44);Y(45);Y(46);Y(48,\"0\",\")\");Y(",
-    "49,\"1\",\"!\");Y(50,\"2\",\"@\");Y(51,\"3\",\"#\");Y(52,\"4\",\"$\");Y",
-    "(53,\"5\",\"%\");Y(54,\"6\",\"^\");Y(55,\"7\",\"&\");Y(56,\"8\",\"*\");",
-    "Y(57,\"9\",\"(\");Y(65,\"a\",\"A\");Y(66,\"b\",\"B\");Y(67,\"c\",\"C\")",
-    ";Y(68,\"d\",\"D\");\nY(69,\"e\",\"E\");Y(70,\"f\",\"F\");Y(71,\"g\",\"G",
-    "\");Y(72,\"h\",\"H\");Y(73,\"i\",\"I\");Y(74,\"j\",\"J\");Y(75,\"k\",\"",
-    "K\");Y(76,\"l\",\"L\");Y(77,\"m\",\"M\");Y(78,\"n\",\"N\");Y(79,\"o\",",
-    "\"O\");Y(80,\"p\",\"P\");Y(81,\"q\",\"Q\");Y(82,\"r\",\"R\");Y(83,\"s\"",
-    ",\"S\");Y(84,\"t\",\"T\");Y(85,\"u\",\"U\");Y(86,\"v\",\"V\");Y(87,\"w",
-    "\",\"W\");Y(88,\"x\",\"X\");Y(89,\"y\",\"Y\");Y(90,\"z\",\"Z\");var sd=",
-    "Y(Ja?{c:91,b:91}:Ia?{c:224,b:91}:{c:0,b:91});Y(Ja?{c:92,b:92}:Ia?{c:224",
-    ",b:93}:{c:0,b:92});Y(Ja?{c:93,b:93}:Ia?{c:0,b:0}:{c:93,b:null});Y({c:96",
-    ",b:96},\"0\");Y({c:97,b:97},\"1\");\nY({c:98,b:98},\"2\");Y({c:99,b:99}",
-    ",\"3\");Y({c:100,b:100},\"4\");Y({c:101,b:101},\"5\");Y({c:102,b:102},",
-    "\"6\");Y({c:103,b:103},\"7\");Y({c:104,b:104},\"8\");Y({c:105,b:105},\"",
-    "9\");Y({c:106,b:106},\"*\");Y({c:107,b:107},\"+\");Y({c:109,b:109},\"-",
-    "\");Y({c:110,b:110},\".\");Y({c:111,b:111},\"/\");Y(144);Y(112);Y(113);",
-    "Y(114);Y(115);Y(116);Y(117);Y(118);Y(119);Y(120);Y(121);Y(122);Y(123);Y",
-    "({c:107,b:187},\"=\",\"+\");Y(108,\",\");Y({c:109,b:189},\"-\",\"_\");Y",
-    "(188,\",\",\"<\");Y(190,\".\",\">\");Y(191,\"/\",\"?\");Y(192,\"`\",\"~",
-    "\");Y(219,\"[\",\"{\");\nY(220,\"\\\\\",\"|\");Y(221,\"]\",\"}\");Y({c:",
-    "59,b:186},\";\",\":\");Y(222,\"'\",'\"');var td=new kd;td.set(1,pd);td.",
-    "set(2,qd);td.set(4,rd);td.set(8,sd);(function(a){var b=new kd;t(ld(a),f",
-    "unction(c){b.set(a.get(c).code,c)});return b})(td);function ud(a,b,c){K",
-    "c.call(this,b,c);this.K=this.j=null;this.C=new z(0,0);this.Y=this.N=!1;",
-    "if(a){n(a.buttonPressed)&&(this.j=a.buttonPressed);try{B(a.elementPress",
-    "ed)&&(this.K=a.elementPressed)}catch(d){this.j=null}this.C=new z(a.clie",
-    "ntXY.x,a.clientXY.y);this.N=!!a.nextClickIsDoubleClick;this.Y=!!a.hasEv",
-    "erInteracted;try{a.element&&B(a.element)&&Lc(this,a.element)}catch(d){t",
-    "his.j=null}}}p(ud,Kc);var Z={};Z[Qc]=[0,1,2,null];Z[dd]=[null,null,2,nu",
-    "ll];Z[Xc]=[0,1,2,null];Z[Pc]=[0,1,2,4];Z[fd]=[0,1,2,4];\nQa&&(Z[Wc]=Z[X",
-    "c],Z[jd]=Z[Xc],Z[id]=[-1,-1,-1,-1],Z[Vc]=Z[id],Z[Uc]=Z[id]);Z[ed]=Z[Qc]",
-    ";Z[Rc]=Z[Xc];Z[Oc]=Z[Pc];var vd={};vd[Rc]=Wc;vd[fd]=id;vd[Pc]=Vc;vd[Oc]",
-    "=Uc;vd[Xc]=jd;ud.prototype.move=function(a,b){var c=tc(a),d=Ec(a);this.",
-    "C.x=b.x+d.left;this.C.y=b.y+d.top;b=this.I();if(a!=b){try{Sa(A(b)).clos",
-    "ed&&(b=null)}catch(e){b=null}b&&(d=b===ka.document.documentElement||b==",
-    "=ka.document.body,b=!this.Y&&d?null:b,wd(this,Pc,a));Lc(this,a);wd(this",
-    ",Oc,b,null,c)}wd(this,fd,null,null,c);this.N=!1};\nud.prototype.scroll=",
-    "function(a){if(0==a)throw new u(13,\"Must scroll a non-zero number of t",
-    "icks.\");for(var b=0<a?-120:120,c=0;c<Math.abs(a);c++)wd(this,bd,null,b",
-    ")};function wd(a,b,c,d,e,f){a.Y=!0;if(Qa){var h=vd[b];if(h&&!a.S(h,a.C,",
-    "xd(a,h),1,MSPointerEvent.MSPOINTER_TYPE_MOUSE,!0,c,e))return!1}return a",
-    ".W(b,a.C,xd(a,b),c,d,e,null,f)}function xd(a,b){if(!(b in Z))return 0;a",
-    "=Z[b][null===a.j?3:a.j];if(null===a)throw new u(13,\"Event does not per",
-    "mit the specified mouse button.\");return a}\nud.prototype.getState=fun",
-    "ction(){return{buttonPressed:this.j,elementPressed:this.K,clientXY:{x:t",
-    "his.C.x,y:this.C.y},nextClickIsDoubleClick:this.N,hasEverInteracted:thi",
-    "s.Y,element:this.I()}};function yd(a,b){this.x=a;this.y=b}p(yd,z);g=yd.",
-    "prototype;g.clone=function(){return new yd(this.x,this.y)};g.scale=z.pr",
-    "ototype.scale;g.normalize=function(){return this.scale(1/Math.sqrt(this",
-    ".x*this.x+this.y*this.y))};g.add=function(a){this.x+=a.x;this.y+=a.y;re",
-    "turn this};g.rotate=function(a){var b=Math.cos(a);a=Math.sin(a);var c=t",
-    "his.y*b+this.x*a;this.x=this.x*b-this.y*a;this.y=c;return this};functio",
-    "n zd(a){var b;(b=qc(a,\"display\"))||(b=a.currentStyle?a.currentStyle.d",
-    "isplay:null);if(\"none\"!=(b||a.style&&a.style.display))b=rc(a);else{b=",
-    "a.style;var c=b.display,d=b.visibility,e=b.position;b.visibility=\"hidd",
-    "en\";b.position=\"absolute\";b.display=\"inline\";var f=rc(a);b.display",
-    "=c;b.position=e;b.visibility=d;b=f}return 0<b.width&&0<b.height||!a.off",
-    "setParent?b:zd(a.offsetParent)};ba(\"_\",function(a,b,c,d){if(!uc(a))th",
-    "row new u(11,\"Element is not currently visible and may not be manipula",
-    "ted\");b:{var e=b||void 0;if(\"scroll\"==Fc(a,e)){if(a.scrollIntoView&&",
-    "(a.scrollIntoView(),\"none\"==Fc(a,e)))break b;for(var f=Ic(a,e),h=Bc(a",
-    ");h;h=Bc(h)){var l=h,q=Ec(l);var y=l;var r=qc(y,\"borderLeftWidth\");va",
-    "r v=qc(y,\"borderRightWidth\");var J=qc(y,\"borderTopWidth\");y=qc(y,\"",
-    "borderBottomWidth\");v=new pc(parseFloat(J),parseFloat(v),parseFloat(y)",
-    ",parseFloat(r));r=f.left-q.left-v.left;q=f.top-q.top-\nv.top;v=l.client",
-    "Height+f.top-f.bottom;l.scrollLeft+=Math.min(r,Math.max(r-(l.clientWidt",
-    "h+f.left-f.right),0));l.scrollTop+=Math.min(q,Math.max(q-v,0))}Fc(a,e)}",
-    "}b?b=new yd(b.x,b.y):(b=zd(a),b=new yd(b.width/2,b.height/2));c=c||new ",
-    "ud;c.move(a,b);if(null!==c.j)throw new u(13,\"Cannot press more than on",
-    "e button or an already pressed button.\");c.j=0;c.K=c.I();if(B(c.I(),\"",
-    "OPTION\")||B(c.I(),\"SELECT\")||wd(c,Rc,null,null,!1,void 0))Qa&&0==c.j",
-    "&&B(c.K,\"OPTION\")&&c.S(gd,c.C,0,1,MSPointerEvent.MSPOINTER_TYPE_MOUSE",
-    ",\n!0),Yc(c);if(null===c.j)throw new u(13,\"Cannot release a button whe",
-    "n no button is pressed.\");c.G&&tc(c.g)&&(a=c.G,b=gb(c.g),!b||a.multipl",
-    "e)&&(c.g.selected=!b,a.multiple&&!(0<=na(Pa,28))||Zc(a,cd));a=tc(c.I())",
-    ";wd(c,Xc,null,null,d,void 0);try{if(0==c.j&&c.I()==c.K){var U=c.C,la=xd",
-    "(c,Qc);if(a||tc(c.g))!c.G&&fb(c.g)&&gb(c.g),c.W(Qc,U,la,null,0,a,void 0",
-    ");c.N&&wd(c,ed);c.N=!c.N;Qa&&0==c.j&&B(c.K,\"OPTION\")&&c.S(hd,new z(0,",
-    "0),0,1,MSPointerEvent.MSPOINTER_TYPE_MOUSE,!1)}else 2==c.j&&wd(c,dd)}ca",
-    "tch(Ad){}Sc=\n{};c.j=null;c.K=null});; return this._.apply(null,argumen",
-    "ts);}.apply({navigator:typeof window!='undefined'?window.navigator:null",
-    ",document:typeof window!='undefined'?window.document:null}, arguments);",
-    "}",
+    "REA\".split(\" \");\nfunction xc(a){return sa(wc,function(b){return B(a",
+    ",b)})||null!=cb(a)&&0<=Number(a.tabIndex)||((B(a,\"TEXTAREA\")?!0:B(a,",
+    "\"INPUT\")?0<=qa(yc,a.type.toLowerCase()):zc(a)?!0:!1)||(B(a,\"INPUT\")",
+    "?\"file\"==a.type.toLowerCase():!1)||Ac(a,\"range\")||Ac(a,\"date\")||A",
+    "c(a,\"month\")||Ac(a,\"week\")||Ac(a,\"time\")||Ac(a,\"datetime-local\"",
+    ")||Ac(a,\"color\"))&&!a.readOnly}var Bc=\"BUTTON INPUT OPTGROUP OPTION ",
+    "SELECT TEXTAREA\".split(\" \");\nfunction vc(a){return sa(Bc,function(b",
+    "){return B(a,b)})?a.disabled?!1:a.parentNode&&1==a.parentNode.nodeType&",
+    "&B(a,\"OPTGROUP\")||B(a,\"OPTION\")?vc(a.parentNode):!$a(a,function(a){",
+    "var b=a.parentNode;if(b&&B(b,\"FIELDSET\")&&b.disabled){if(!B(a,\"LEGEN",
+    "D\"))return!0;for(;a=k(a.previousElementSibling)?a.previousElementSibli",
+    "ng:Va(a.previousSibling);)if(B(a,\"LEGEND\"))return!0}return!1},!0):!0}",
+    "var yc=\"text search tel url email password number\".split(\" \");\nfun",
+    "ction Ac(a,b){return B(a,\"INPUT\")?a.type.toLowerCase()==b:!1}function",
+    " zc(a){function b(a){return\"inherit\"==a.contentEditable?(a=Cc(a))?b(a",
+    "):!1:\"true\"==a.contentEditable}return k(a.contentEditable)?k(a.isCont",
+    "entEditable)?a.isContentEditable:b(a):!1}function Cc(a){for(a=a.parentN",
+    "ode;a&&1!=a.nodeType&&9!=a.nodeType&&11!=a.nodeType;)a=a.parentNode;ret",
+    "urn B(a)?a:null}\nfunction T(a,b){b=pa(b);if(\"float\"==b||\"cssFloat\"",
+    "==b||\"styleFloat\"==b)b=\"cssFloat\";a=qc(a,b)||Dc(a,b);if(null===a)a=",
+    "null;else if(0<=qa(ya,b)){b:{var c=a.match(Ba);if(c){b=Number(c[1]);var",
+    " d=Number(c[2]),e=Number(c[3]),c=Number(c[4]);if(0<=b&&255>=b&&0<=d&&25",
+    "5>=d&&0<=e&&255>=e&&0<=c&&1>=c){b=[b,d,e,c];break b}}b=null}if(!b)b:{if",
+    "(e=a.match(Ca))if(b=Number(e[1]),d=Number(e[2]),e=Number(e[3]),0<=b&&25",
+    "5>=b&&0<=d&&255>=d&&0<=e&&255>=e){b=[b,d,e,1];break b}b=null}if(!b)b:{b",
+    "=a.toLowerCase();d=xa[b.toLowerCase()];\nif(!d&&(d=\"#\"==b.charAt(0)?b",
+    ":\"#\"+b,4==d.length&&(d=d.replace(za,\"#$1$1$2$2$3$3\")),!Aa.test(d)))",
+    "{b=null;break b}b=[parseInt(d.substr(1,2),16),parseInt(d.substr(3,2),16",
+    "),parseInt(d.substr(5,2),16),1]}a=b?\"rgba(\"+b.join(\", \")+\")\":a}re",
+    "turn a}function Dc(a,b){var c=a.currentStyle||a.style,d=c[b];!k(d)&&ea(",
+    "c.getPropertyValue)&&(d=c.getPropertyValue(b));return\"inherit\"!=d?k(d",
+    ")?d:null:(a=Cc(a))?Dc(a,b):null}\nfunction Ec(a,b,c){function d(a){var ",
+    "b=Fc(a);return 0<b.height&&0<b.width?!0:B(a,\"PATH\")&&(0<b.height||0<b",
+    ".width)?(a=T(a,\"stroke-width\"),!!a&&0<parseInt(a,10)):\"hidden\"!=T(a",
+    ",\"overflow\")&&sa(a.childNodes,function(a){return 3==a.nodeType||B(a)&",
+    "&d(a)})}function e(a){return Gc(a)==V&&ta(a.childNodes,function(a){retu",
+    "rn!B(a)||e(a)||!d(a)})}if(!B(a))throw Error(\"Argument to isShown must ",
+    "be of type Element\");if(B(a,\"BODY\"))return!0;if(B(a,\"OPTION\")||B(a",
+    ",\"OPTGROUP\"))return a=$a(a,function(a){return B(a,\"SELECT\")}),\n!!a",
+    "&&Ec(a,!0,c);var f=Hc(a);if(f)return!!f.sa&&0<f.rect.width&&0<f.rect.he",
+    "ight&&Ec(f.sa,b,c);if(B(a,\"INPUT\")&&\"hidden\"==a.type.toLowerCase()|",
+    "|B(a,\"NOSCRIPT\"))return!1;f=T(a,\"visibility\");return\"collapse\"!=f",
+    "&&\"hidden\"!=f&&c(a)&&(b||0!=Ic(a))&&d(a)?!e(a):!1}\nfunction uc(a){fu",
+    "nction b(a){if(B(a)&&\"none\"==T(a,\"display\"))return!1;var c;(c=a.par",
+    "entNode)&&c.shadowRoot&&void 0!==a.assignedSlot?c=a.assignedSlot?a.assi",
+    "gnedSlot.parentNode:null:a.getDestinationInsertionPoints&&(a=a.getDesti",
+    "nationInsertionPoints(),0<a.length&&(c=a[a.length-1]));return sc&&c ins",
+    "tanceof ShadowRoot||c&&(9==c.nodeType||11==c.nodeType)?!0:!!c&&b(c)}ret",
+    "urn Ec(a,!0,b)}var V=\"hidden\";\nfunction Gc(a,b){function c(a){functi",
+    "on b(a){return a==h?!0:0==T(a,\"display\").lastIndexOf(\"inline\",0)||",
+    "\"absolute\"==c&&\"static\"==T(a,\"position\")?!1:!0}var c=T(a,\"positi",
+    "on\");if(\"fixed\"==c)return y=!0,a==h?null:h;for(a=Cc(a);a&&!b(a);)a=C",
+    "c(a);return a}function d(a){var b=a;if(\"visible\"==q)if(a==h&&l)b=l;el",
+    "se if(a==l)return{x:\"visible\",y:\"visible\"};b={x:T(b,\"overflow-x\")",
+    ",y:T(b,\"overflow-y\")};a==h&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"",
+    "visible\"==b.y?\"auto\":b.y);return b}function e(a){if(a==h){var b=(new",
+    " bb(f)).R;\na=b.scrollingElement?b.scrollingElement:b.body||b.documentE",
+    "lement;b=b.parentWindow||b.defaultView;a=new z(b.pageXOffset||a.scrollL",
+    "eft,b.pageYOffset||a.scrollTop)}else a=new z(a.scrollLeft,a.scrollTop);",
+    "return a}b=Jc(a,b);var f=A(a),h=f.documentElement,l=f.body,q=T(h,\"over",
+    "flow\"),y;for(a=c(a);a;a=c(a)){var r=d(a);if(\"visible\"!=r.x||\"visibl",
+    "e\"!=r.y){var v=Fc(a);if(0==v.width||0==v.height)return V;var J=b.right",
+    "<v.left,U=b.bottom<v.top;if(J&&\"hidden\"==r.x||U&&\"hidden\"==r.y)retu",
+    "rn V;if(J&&\"visible\"!=r.x||\nU&&\"visible\"!=r.y){J=e(a);U=b.bottom<v",
+    ".top-J.y;if(b.right<v.left-J.x&&\"visible\"!=r.x||U&&\"visible\"!=r.x)r",
+    "eturn V;b=Gc(a);return b==V?V:\"scroll\"}J=b.left>=v.left+v.width;v=b.t",
+    "op>=v.top+v.height;if(J&&\"hidden\"==r.x||v&&\"hidden\"==r.y)return V;i",
+    "f(J&&\"visible\"!=r.x||v&&\"visible\"!=r.y){if(y&&(r=e(a),b.left>=h.scr",
+    "ollWidth-r.x||b.right>=h.scrollHeight-r.y))return V;b=Gc(a);return b==V",
+    "?V:\"scroll\"}}}return\"none\"}\nfunction Fc(a){var b=Hc(a);if(b)return",
+    " b.rect;if(B(a,\"HTML\"))return a=A(a),a=(Sa(a)||window).document,a=\"C",
+    "SS1Compat\"==a.compatMode?a.documentElement:a.body,a=new Ra(a.clientWid",
+    "th,a.clientHeight),new S(0,0,a.width,a.height);try{var c=a.getBoundingC",
+    "lientRect()}catch(d){return new S(0,0,0,0)}return new S(c.left,c.top,c.",
+    "right-c.left,c.bottom-c.top)}\nfunction Hc(a){var b=B(a,\"MAP\");if(!b&",
+    "&!B(a,\"AREA\"))return null;var c=b?a:B(a.parentNode,\"MAP\")?a.parentN",
+    "ode:null,d=null,e=null;c&&c.name&&(d=R.Ja('/descendant::*[@usemap = \"#",
+    "'+c.name+'\"]',A(c)))&&(e=Fc(d),b||\"default\"==a.shape.toLowerCase()||",
+    "(a=Kc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.min(Math.max(a.t",
+    "op,0),e.height),e=new S(b+e.left,c+e.top,Math.min(a.width,e.width-b),Ma",
+    "th.min(a.height,e.height-c))));return{sa:d,rect:e||new S(0,0,0,0)}}\nfu",
+    "nction Kc(a){var b=a.shape.toLowerCase();a=a.coords.split(\",\");if(\"r",
+    "ect\"==b&&4==a.length){var b=a[0],c=a[1];return new S(b,c,a[2]-b,a[3]-c",
+    ")}if(\"circle\"==b&&3==a.length)return b=a[2],new S(a[0]-b,a[1]-b,2*b,2",
+    "*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f+1<a",
+    ".length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1])",
+    ",e=Math.max(e,a[f+1]);return new S(b,c,d-b,e-c)}return new S(0,0,0,0)}",
+    "\nfunction Jc(a,b){a=Fc(a);a=new pc(a.top,a.left+a.width,a.top+a.height",
+    ",a.left);b&&(b=b instanceof S?b:new S(b.x,b.y,1,1),a.left=Math.min(Math",
+    ".max(a.left+b.left,a.left),a.right),a.top=Math.min(Math.max(a.top+b.top",
+    ",a.top),a.bottom),a.right=Math.min(Math.max(a.left+b.width,a.left),a.ri",
+    "ght),a.bottom=Math.min(Math.max(a.top+b.height,a.top),a.bottom));return",
+    " a}function Ic(a){var b=1,c=T(a,\"opacity\");c&&(b=Number(c));(a=Cc(a))",
+    "&&(b*=Ic(a));return b};function Lc(a,b){this.g=ka.document.documentElem",
+    "ent;this.G=null;var c=ab(A(this.g));c&&Mc(this,c);this.$=a||new Nc;this",
+    ".pa=b||new Oc}Lc.prototype.I=function(){return this.g};function Mc(a,b)",
+    "{a.g=b;a.G=B(b,\"OPTION\")?$a(b,function(a){return B(a,\"SELECT\")}):nu",
+    "ll}\nLc.prototype.W=function(a,b,c,d,e,f,h,l){if(!f&&!tc(this.g))return",
+    "!1;if(d&&Pc!=a&&Qc!=a)throw new u(12,\"Event type does not allow relate",
+    "d target: \"+a);b={clientX:b.x,clientY:b.y,button:c,altKey:0!=(this.$.c",
+    "a&4),ctrlKey:0!=(this.$.ca&2),shiftKey:0!=(this.$.ca&1),metaKey:0!=(thi",
+    "s.$.ca&8),wheelDelta:e||0,relatedTarget:d||null,count:l||1};h=h||1;c=th",
+    "is.g;a!=Rc&&a!=Sc&&h in Tc?c=Tc[h]:this.G&&(c=Uc(this,a));return c?this",
+    ".pa.W(c,a,b):!0};\nLc.prototype.S=function(a,b,c,d,e,f,h,l){if(!l&&!tc(",
+    "this.g))return!1;if(h&&Vc!=a&&Wc!=a)throw new u(12,\"Event type does no",
+    "t allow related target: \"+a);b={clientX:b.x,clientY:b.y,button:c,altKe",
+    "y:!1,ctrlKey:!1,shiftKey:!1,metaKey:!1,relatedTarget:h||null,width:0,he",
+    "ight:0,pressure:0,rotation:0,pointerId:d,tiltX:0,tiltY:0,pointerType:e,",
+    "isPrimary:f};c=this.G?Uc(this,a):this.g;Tc[d]&&(c=Tc[d]);d=Sa(A(this.g)",
+    ");if(d&&a==Xc){var q=d.Element.prototype.msSetPointerCapture;d.Element.",
+    "prototype.msSetPointerCapture=\nfunction(a){Tc[a]=this}}a=c?this.pa.S(c",
+    ",a,b):!0;q&&(d.Element.prototype.msSetPointerCapture=q);return a};funct",
+    "ion Uc(a,b){switch(b){case Rc:case Yc:return a.G.multiple?a.g:a.G;defau",
+    "lt:return a.G.multiple?a.g:null}}function Zc(a){var b=$a(a.g,function(a",
+    "){return!!a&&B(a)&&xc(a)},!0),b=b||a.g;a=ab(A(b));if(b!=a){if(a&&ea(a.b",
+    "lur)&&!B(a,\"BODY\"))try{a.blur()}catch(c){throw c;}ea(b.focus)&&b.focu",
+    "s()}}function Nc(){this.ca=0}var Tc={};function Oc(){}Oc.prototype.W=fu",
+    "nction(a,b,c){return $c(a,b,c)};\nOc.prototype.S=function(a,b,c){return",
+    " $c(a,b,c)};Na();Na();function ad(a,b,c){this.B=a;this.la=b;this.ma=c}a",
+    "d.prototype.create=function(a){a=A(a).createEvent(\"HTMLEvents\");a.ini",
+    "tEvent(this.B,this.la,this.ma);return a};ad.prototype.toString=function",
+    "(){return this.B};function W(a,b,c){ad.call(this,a,b,c)}p(W,ad);\nW.pro",
+    "totype.create=function(a,b){if(this==bd)throw new u(9,\"Browser does no",
+    "t support a mouse pixel scroll event.\");var c=A(a);a=Sa(c);c=c.createE",
+    "vent(\"MouseEvents\");this==cd&&(c.wheelDelta=b.wheelDelta);c.initMouse",
+    "Event(this.B,this.la,this.ma,a,1,b.clientX,b.clientY,b.clientX,b.client",
+    "Y,b.ctrlKey,b.altKey,b.shiftKey,b.metaKey,b.button,b.relatedTarget);ret",
+    "urn c};function X(a,b,c){ad.call(this,a,b,c)}p(X,ad);X.prototype.create",
+    "=function(){throw new u(9,\"Browser does not support MSPointer events.",
+    "\");};\nvar dd=new ad(\"change\",!0,!1),Rc=new W(\"click\",!0,!0),ed=ne",
+    "w W(\"contextmenu\",!0,!0),fd=new W(\"dblclick\",!0,!0),Sc=new W(\"mous",
+    "edown\",!0,!0),gd=new W(\"mousemove\",!0,!1),Qc=new W(\"mouseout\",!0,!",
+    "0),Pc=new W(\"mouseover\",!0,!0),Yc=new W(\"mouseup\",!0,!0),cd=new W(",
+    "\"mousewheel\",!0,!0),bd=new W(\"MozMousePixelScroll\",!0,!0),hd=new X(",
+    "\"MSGotPointerCapture\",!0,!1),id=new X(\"MSLostPointerCapture\",!0,!1)",
+    ",Xc=new X(\"MSPointerDown\",!0,!0),jd=new X(\"MSPointerMove\",!0,!0),Vc",
+    "=new X(\"MSPointerOver\",!0,!0),Wc=new X(\"MSPointerOut\",\n!0,!0),kd=n",
+    "ew X(\"MSPointerUp\",!0,!0);function $c(a,b,c){b=b.create(a,c);\"isTrus",
+    "ted\"in b||(b.isTrusted=!1);return a.dispatchEvent(b)};function ld(a,b)",
+    "{this.D={};this.h=[];this.M=0;var c=arguments.length;if(1<c){if(c%2)thr",
+    "ow Error(\"Uneven number of arguments\");for(var d=0;d<c;d+=2)this.set(",
+    "arguments[d],arguments[d+1])}else a&&this.addAll(a)}function md(a){nd(a",
+    ");return a.h.concat()}g=ld.prototype;g.clear=function(){this.D={};this.",
+    "M=this.h.length=0};g.remove=function(a){return Object.prototype.hasOwnP",
+    "roperty.call(this.D,a)?(delete this.D[a],this.M--,this.h.length>2*this.",
+    "M&&nd(this),!0):!1};\nfunction nd(a){var b,c;if(a.M!=a.h.length){for(b=",
+    "c=0;c<a.h.length;){var d=a.h[c];Object.prototype.hasOwnProperty.call(a.",
+    "D,d)&&(a.h[b++]=d);c++}a.h.length=b}if(a.M!=a.h.length){var e={};for(b=",
+    "c=0;c<a.h.length;)d=a.h[c],Object.prototype.hasOwnProperty.call(e,d)||(",
+    "a.h[b++]=d,e[d]=1),c++;a.h.length=b}}g.get=function(a,b){return Object.",
+    "prototype.hasOwnProperty.call(this.D,a)?this.D[a]:b};g.set=function(a,b",
+    "){Object.prototype.hasOwnProperty.call(this.D,a)||(this.M++,this.h.push",
+    "(a));this.D[a]=b};\ng.addAll=function(a){if(a instanceof ld){var b=md(a",
+    ");nd(a);for(var c=[],d=0;d<a.h.length;d++)c.push(a.D[a.h[d]]);a=c}else{",
+    "b=[];var d=0;for(e in a)b[d++]=e;d=[];var e=0;for(c in a)d[e++]=a[c];a=",
+    "d}for(c=0;c<b.length;c++)this.set(b[c],a[c])};g.forEach=function(a,b){f",
+    "or(var c=md(this),d=0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b",
+    ",f,e,this)}};g.clone=function(){return new ld(this)};var od={};function",
+    " Y(a,b,c){fa(a)&&(a=a.b);a=new pd(a);!b||b in od&&!c||(od[b]={key:a,shi",
+    "ft:!1},c&&(od[c]={key:a,shift:!0}));return a}function pd(a){this.code=a",
+    "}Y(8);Y(9);Y(13);var qd=Y(16),rd=Y(17),sd=Y(18);Y(19);Y(20);Y(27);Y(32,",
+    "\" \");Y(33);Y(34);Y(35);Y(36);Y(37);Y(38);Y(39);Y(40);Y(44);Y(45);Y(46",
+    ");Y(48,\"0\",\")\");Y(49,\"1\",\"!\");Y(50,\"2\",\"@\");Y(51,\"3\",\"#",
+    "\");Y(52,\"4\",\"$\");Y(53,\"5\",\"%\");Y(54,\"6\",\"^\");Y(55,\"7\",\"",
+    "&\");Y(56,\"8\",\"*\");Y(57,\"9\",\"(\");Y(65,\"a\",\"A\");Y(66,\"b\",",
+    "\"B\");Y(67,\"c\",\"C\");Y(68,\"d\",\"D\");\nY(69,\"e\",\"E\");Y(70,\"f",
+    "\",\"F\");Y(71,\"g\",\"G\");Y(72,\"h\",\"H\");Y(73,\"i\",\"I\");Y(74,\"",
+    "j\",\"J\");Y(75,\"k\",\"K\");Y(76,\"l\",\"L\");Y(77,\"m\",\"M\");Y(78,",
+    "\"n\",\"N\");Y(79,\"o\",\"O\");Y(80,\"p\",\"P\");Y(81,\"q\",\"Q\");Y(82",
+    ",\"r\",\"R\");Y(83,\"s\",\"S\");Y(84,\"t\",\"T\");Y(85,\"u\",\"U\");Y(8",
+    "6,\"v\",\"V\");Y(87,\"w\",\"W\");Y(88,\"x\",\"X\");Y(89,\"y\",\"Y\");Y(",
+    "90,\"z\",\"Z\");var td=Y(Ja?{c:91,b:91}:Ia?{c:224,b:91}:{c:0,b:91});Y(J",
+    "a?{c:92,b:92}:Ia?{c:224,b:93}:{c:0,b:92});Y(Ja?{c:93,b:93}:Ia?{c:0,b:0}",
+    ":{c:93,b:null});Y({c:96,b:96},\"0\");Y({c:97,b:97},\"1\");\nY({c:98,b:9",
+    "8},\"2\");Y({c:99,b:99},\"3\");Y({c:100,b:100},\"4\");Y({c:101,b:101},",
+    "\"5\");Y({c:102,b:102},\"6\");Y({c:103,b:103},\"7\");Y({c:104,b:104},\"",
+    "8\");Y({c:105,b:105},\"9\");Y({c:106,b:106},\"*\");Y({c:107,b:107},\"+",
+    "\");Y({c:109,b:109},\"-\");Y({c:110,b:110},\".\");Y({c:111,b:111},\"/\"",
+    ");Y(144);Y(112);Y(113);Y(114);Y(115);Y(116);Y(117);Y(118);Y(119);Y(120)",
+    ";Y(121);Y(122);Y(123);Y({c:107,b:187},\"=\",\"+\");Y(108,\",\");Y({c:10",
+    "9,b:189},\"-\",\"_\");Y(188,\",\",\"<\");Y(190,\".\",\">\");Y(191,\"/\"",
+    ",\"?\");Y(192,\"`\",\"~\");Y(219,\"[\",\"{\");\nY(220,\"\\\\\",\"|\");Y",
+    "(221,\"]\",\"}\");Y({c:59,b:186},\";\",\":\");Y(222,\"'\",'\"');var ud=",
+    "new ld;ud.set(1,qd);ud.set(2,rd);ud.set(4,sd);ud.set(8,td);(function(a)",
+    "{var b=new ld;t(md(a),function(c){b.set(a.get(c).code,c)});return b})(u",
+    "d);function vd(a,b,c){Lc.call(this,b,c);this.K=this.j=null;this.C=new z",
+    "(0,0);this.Y=this.N=!1;if(a){n(a.buttonPressed)&&(this.j=a.buttonPresse",
+    "d);try{B(a.elementPressed)&&(this.K=a.elementPressed)}catch(d){this.j=n",
+    "ull}this.C=new z(a.clientXY.x,a.clientXY.y);this.N=!!a.nextClickIsDoubl",
+    "eClick;this.Y=!!a.hasEverInteracted;try{a.element&&B(a.element)&&Mc(thi",
+    "s,a.element)}catch(d){this.j=null}}}p(vd,Lc);var Z={};Z[Rc]=[0,1,2,null",
+    "];Z[ed]=[null,null,2,null];Z[Yc]=[0,1,2,null];Z[Qc]=[0,1,2,4];Z[gd]=[0,",
+    "1,2,4];\nQa&&(Z[Xc]=Z[Yc],Z[kd]=Z[Yc],Z[jd]=[-1,-1,-1,-1],Z[Wc]=Z[jd],Z",
+    "[Vc]=Z[jd]);Z[fd]=Z[Rc];Z[Sc]=Z[Yc];Z[Pc]=Z[Qc];var wd={};wd[Sc]=Xc;wd[",
+    "gd]=jd;wd[Qc]=Wc;wd[Pc]=Vc;wd[Yc]=kd;vd.prototype.move=function(a,b){va",
+    "r c=tc(a),d=Fc(a);this.C.x=b.x+d.left;this.C.y=b.y+d.top;b=this.I();if(",
+    "a!=b){try{Sa(A(b)).closed&&(b=null)}catch(e){b=null}b&&(d=b===ka.docume",
+    "nt.documentElement||b===ka.document.body,b=!this.Y&&d?null:b,xd(this,Qc",
+    ",a));Mc(this,a);xd(this,Pc,b,null,c)}xd(this,gd,null,null,c);this.N=!1}",
+    ";\nvd.prototype.scroll=function(a){if(0==a)throw new u(13,\"Must scroll",
+    " a non-zero number of ticks.\");for(var b=0<a?-120:120,c=0;c<Math.abs(a",
+    ");c++)xd(this,cd,null,b)};function xd(a,b,c,d,e,f){a.Y=!0;if(Qa){var h=",
+    "wd[b];if(h&&!a.S(h,a.C,yd(a,h),1,MSPointerEvent.MSPOINTER_TYPE_MOUSE,!0",
+    ",c,e))return!1}return a.W(b,a.C,yd(a,b),c,d,e,null,f)}function yd(a,b){",
+    "if(!(b in Z))return 0;a=Z[b][null===a.j?3:a.j];if(null===a)throw new u(",
+    "13,\"Event does not permit the specified mouse button.\");return a}\nvd",
+    ".prototype.getState=function(){return{buttonPressed:this.j,elementPress",
+    "ed:this.K,clientXY:{x:this.C.x,y:this.C.y},nextClickIsDoubleClick:this.",
+    "N,hasEverInteracted:this.Y,element:this.I()}};function zd(a,b){this.x=a",
+    ";this.y=b}p(zd,z);g=zd.prototype;g.clone=function(){return new zd(this.",
+    "x,this.y)};g.scale=z.prototype.scale;g.normalize=function(){return this",
+    ".scale(1/Math.sqrt(this.x*this.x+this.y*this.y))};g.add=function(a){thi",
+    "s.x+=a.x;this.y+=a.y;return this};g.rotate=function(a){var b=Math.cos(a",
+    ");a=Math.sin(a);var c=this.y*b+this.x*a;this.x=this.x*b-this.y*a;this.y",
+    "=c;return this};function Ad(a){var b;(b=qc(a,\"display\"))||(b=a.curren",
+    "tStyle?a.currentStyle.display:null);if(\"none\"!=(b||a.style&&a.style.d",
+    "isplay))b=rc(a);else{b=a.style;var c=b.display,d=b.visibility,e=b.posit",
+    "ion;b.visibility=\"hidden\";b.position=\"absolute\";b.display=\"inline",
+    "\";var f=rc(a);b.display=c;b.position=e;b.visibility=d;b=f}return 0<b.w",
+    "idth&&0<b.height||!a.offsetParent?b:Ad(a.offsetParent)};ba(\"_\",functi",
+    "on(a,b,c,d){if(!uc(a))throw new u(11,\"Element is not currently visible",
+    " and may not be manipulated\");b:{var e=b||void 0;if(\"scroll\"==Gc(a,e",
+    ")){if(a.scrollIntoView&&(a.scrollIntoView(),\"none\"==Gc(a,e)))break b;",
+    "for(var f=Jc(a,e),h=Cc(a);h;h=Cc(h)){var l=h,q=Fc(l);var y=l;var r=qc(y",
+    ",\"borderLeftWidth\");var v=qc(y,\"borderRightWidth\");var J=qc(y,\"bor",
+    "derTopWidth\");y=qc(y,\"borderBottomWidth\");v=new pc(parseFloat(J),par",
+    "seFloat(v),parseFloat(y),parseFloat(r));r=f.left-q.left-v.left;q=f.top-",
+    "q.top-\nv.top;v=l.clientHeight+f.top-f.bottom;l.scrollLeft+=Math.min(r,",
+    "Math.max(r-(l.clientWidth+f.left-f.right),0));l.scrollTop+=Math.min(q,M",
+    "ath.max(q-v,0))}Gc(a,e)}}b?b=new zd(b.x,b.y):(b=Ad(a),b=new zd(b.width/",
+    "2,b.height/2));c=c||new vd;c.move(a,b);if(null!==c.j)throw new u(13,\"C",
+    "annot press more than one button or an already pressed button.\");c.j=0",
+    ";c.K=c.I();if(B(c.I(),\"OPTION\")||B(c.I(),\"SELECT\")||xd(c,Sc,null,nu",
+    "ll,!1,void 0))Qa&&0==c.j&&B(c.K,\"OPTION\")&&c.S(hd,c.C,0,1,MSPointerEv",
+    "ent.MSPOINTER_TYPE_MOUSE,\n!0),Zc(c);if(null===c.j)throw new u(13,\"Can",
+    "not release a button when no button is pressed.\");c.G&&tc(c.g)&&(a=c.G",
+    ",b=gb(c.g),!b||a.multiple)&&(c.g.selected=!b,a.multiple&&!(0<=na(Pa,28)",
+    ")||$c(a,dd));a=tc(c.I());xd(c,Yc,null,null,d,void 0);try{if(0==c.j&&c.I",
+    "()==c.K){var U=c.C,ma=yd(c,Rc);if(a||tc(c.g))!c.G&&fb(c.g)&&gb(c.g),c.W",
+    "(Rc,U,ma,null,0,a,void 0);c.N&&xd(c,fd);c.N=!c.N;Qa&&0==c.j&&B(c.K,\"OP",
+    "TION\")&&c.S(id,new z(0,0),0,1,MSPointerEvent.MSPOINTER_TYPE_MOUSE,!1)}",
+    "else 2==c.j&&xd(c,ed)}catch(Bd){}Tc=\n{};c.j=null;c.K=null});; return t",
+    "his._.apply(null,arguments);}.apply({navigator:typeof window!='undefine",
+    "d'?window.navigator:null,document:typeof window!='undefined'?window.doc",
+    "ument:null}, arguments);}",
     NULL
 };
 
@@ -1657,7 +1663,7 @@
     "a,d){switch(e(a)){case \"string\":case \"number\":case \"boolean\":retu",
     "rn a;case \"function\":return a.toString();case \"array\":return u(a,fu",
     "nction(a){return b(a,d)});case \"object\":if(0<=d.indexOf(a))throw new ",
-    "q(13,\"Recursive object cannot be transferred\");if(y(a,\"nodeType\")&&",
+    "q(17,\"Recursive object cannot be transferred\");if(y(a,\"nodeType\")&&",
     "(1==a.nodeType||9==a.nodeType)){var c={};c.ELEMENT=G(a);return c}if(y(a",
     ",\"document\"))return c={},c.WINDOW=G(a),c;d.push(a);if(k(a))return u(a",
     ",function(a){return b(a,d)});a=w(a,function(a,b){return\"number\"==type",
@@ -1756,7 +1762,7 @@
     "){function b(a,d){switch(e(a)){case \"string\":case \"number\":case \"b",
     "oolean\":return a;case \"function\":return a.toString();case \"array\":",
     "return u(a,function(a){return b(a,d)});case \"object\":if(0<=d.indexOf(",
-    "a))throw new q(13,\"Recursive object cannot be transferred\");if(x(a,\"",
+    "a))throw new q(17,\"Recursive object cannot be transferred\");if(x(a,\"",
     "nodeType\")&&(1==a.nodeType||9==a.nodeType)){var c={};c.ELEMENT=F(a);re",
     "turn c}if(x(a,\"document\"))return c={},c.WINDOW=F(a),c;d.push(a);if(h(",
     "a))return u(a,function(a){return b(a,d)});a=v(a,function(a,b){return\"n",
@@ -1848,7 +1854,7 @@
     "().indexOf(\"native code\")?fa:ga;return ha.apply(null,arguments)}\nfun",
     "ction ia(a,b){var c=Array.prototype.slice.call(arguments,1);return func",
     "tion(){var b=c.slice();b.push.apply(b,arguments);return a.apply(this,b)",
-    "}}function r(a,b){function c(){}c.prototype=b.prototype;a.xa=b.prototyp",
+    "}}function q(a,b){function c(){}c.prototype=b.prototype;a.xa=b.prototyp",
     "e;a.prototype=new c;a.prototype.constructor=a;a.wa=function(a,c,f){for(",
     "var d=Array(arguments.length-2),e=2;e<arguments.length;e++)d[e-2]=argum",
     "ents[e];return b.prototype[c].apply(a,d)}};var ja=window;function t(a,b",
@@ -1856,7 +1862,7 @@
     "lace(/((?:^|\\s+)[a-z])/g,function(a){return a.toUpperCase().replace(/^",
     "[\\s\\xa0]+/g,\"\")});b=a.length-5;if(0>b||a.indexOf(\"Error\",b)!=b)a+",
     "=\"Error\";this.name=a;a=Error(this.message);a.name=this.name;this.stac",
-    "k=a.stack||\"\"}r(t,Error);var ka=\"unknown error\",v={15:\"element not",
+    "k=a.stack||\"\"}q(t,Error);var ka=\"unknown error\",v={15:\"element not",
     " selectable\",11:\"element not visible\"};v[31]=ka;v[30]=ka;v[24]=\"inv",
     "alid cookie domain\";v[29]=\"invalid element coordinates\";v[12]=\"inva",
     "lid element state\";\nv[32]=\"invalid selector\";v[51]=\"invalid select",
@@ -1915,13 +1921,13 @@
     "ocumentPosition)return a.compareDocumentPosition(b)&2?1:-1;if(\"sourceI",
     "ndex\"in a||a.parentNode&&\"sourceIndex\"in a.parentNode){var c=1==a.no",
     "deType,d=1==b.nodeType;if(c&&d)return a.sourceIndex-b.sourceIndex;var e",
-    "=a.parentNode,f=b.parentNode;return e==f?Fa(a,b):!c&&Da(e,b)?-1*Ha(a,b)",
+    "=a.parentNode,f=b.parentNode;return e==f?Ga(a,b):!c&&Da(e,b)?-1*Ha(a,b)",
     ":!d&&Da(f,a)?Ha(b,a):(c?a.sourceIndex:e.sourceIndex)-(d?b.sourceIndex:f",
     ".sourceIndex)}d=z(a);c=d.createRange();c.selectNode(a);c.collapse(!0);a",
     "=d.createRange();a.selectNode(b);\na.collapse(!0);return c.compareBound",
     "aryPoints(aa.Range.START_TO_END,a)}function Ha(a,b){var c=a.parentNode;",
-    "if(c==b)return-1;for(;b.parentNode!=c;)b=b.parentNode;return Fa(b,a)}fu",
-    "nction Fa(a,b){for(;b=b.previousSibling;)if(b==a)return-1;return 1}func",
+    "if(c==b)return-1;for(;b.parentNode!=c;)b=b.parentNode;return Ga(b,a)}fu",
+    "nction Ga(a,b){for(;b=b.previousSibling;)if(b==a)return-1;return 1}func",
     "tion z(a){return 9==a.nodeType?a:a.ownerDocument||a.document}function B",
     "a(a){if(a&&\"number\"==typeof a.length){if(ea(a))return\"function\"==ty",
     "peof a.item||\"string\"==typeof a.item;if(p(a))return\"function\"==type",
@@ -2089,7 +2095,7 @@
     "c){I.call(this,a.f);this.V=a;this.ca=b;this.ia=c;this.u=b.c()||c.c();th",
     "is.h=b.h||c.h;this.V==lb&&(c.h||c.c()||4==c.f||0==c.f||!b.w()?b.h||b.c(",
     ")||4==b.f||0==b.f||!c.w()||(this.I={name:c.w().name,G:b}):this.I={name:",
-    "b.w().name,G:c})}r(kb,I);\nfunction mb(a,b,c,d,e){b=b.evaluate(d);c=c.e",
+    "b.w().name,G:c})}q(kb,I);\nfunction mb(a,b,c,d,e){b=b.evaluate(d);c=c.e",
     "valuate(d);var f;if(b instanceof G&&c instanceof G){b=b.iterator();for(",
     "d=b.next();d;d=b.next())for(e=c.iterator(),f=e.next();f;f=e.next())if(a",
     "(F(d),F(f)))return!0;return!1}if(b instanceof G||c instanceof G){b inst",
@@ -2119,7 +2125,7 @@
     "b(a,c)&&jb(b,c)});N(\"or\",1,2,function(a,b,c){return jb(a,c)||jb(b,c)}",
     ");function pb(a,b){if(b.s()&&4!=a.f)throw Error(\"Primary expression mu",
     "st evaluate to nodeset if filter has predicate(s).\");I.call(this,a.f);",
-    "this.ha=a;this.b=b;this.u=a.c();this.h=a.h}r(pb,I);pb.prototype.evaluat",
+    "this.ha=a;this.b=b;this.u=a.c();this.h=a.h}q(pb,I);pb.prototype.evaluat",
     "e=function(a){a=this.ha.evaluate(a);return qb(this.b,a)};pb.prototype.t",
     "oString=function(){var a=\"Filter:\"+J(this.ha);return a+=J(this.b)};fu",
     "nction rb(a,b){if(b.length<a.fa)throw Error(\"Function \"+a.i+\" expect",
@@ -2129,7 +2135,7 @@
     "hrow Error(\"Argument \"+d+\" to function \"+a.i+\" is not of type Node",
     "set: \"+b);});I.call(this,a.f);this.L=a;this.R=b;hb(this,a.u||sa(b,func",
     "tion(a){return a.c()}));ib(this,a.pa&&!b.length||a.oa&&!!b.length||sa(b",
-    ",function(a){return a.h}))}\nr(rb,I);rb.prototype.evaluate=function(a){",
+    ",function(a){return a.h}))}\nq(rb,I);rb.prototype.evaluate=function(a){",
     "return this.L.o.apply(null,va(a,this.R))};rb.prototype.toString=functio",
     "n(){var a=\"Function: \"+this.L;if(this.R.length)var b=ra(this.R,functi",
     "on(a,b){return a+J(b)},\"Arguments:\"),a=a+J(b);return a};function sb(a",
@@ -2183,7 +2189,7 @@
     "e.matches=function(a){return null===this.F||this.F==a.nodeType};H.proto",
     "type.getName=function(){return this.la};\nH.prototype.toString=function",
     "(){var a=\"Kind Test: \"+this.la;null===this.da||(a+=J(this.da));return",
-    " a};function vb(a){I.call(this,3);this.ka=a.substring(1,a.length-1)}r(v",
+    " a};function vb(a){I.call(this,3);this.ka=a.substring(1,a.length-1)}q(v",
     "b,I);vb.prototype.evaluate=function(){return this.ka};vb.prototype.toSt",
     "ring=function(){return\"Literal: \"+this.ka};function wb(a,b){this.i=a.",
     "toLowerCase();a=\"*\"==this.i?\"*\":\"http://www.w3.org/1999/xhtml\";th",
@@ -2194,14 +2200,14 @@
     "ml\")};wb.prototype.getName=function(){return this.i};\nwb.prototype.to",
     "String=function(){return\"Name Test: \"+(\"http://www.w3.org/1999/xhtml",
     "\"==this.N?\"\":this.N+\":\")+this.i};function xb(a){I.call(this,1);thi",
-    "s.ma=a}r(xb,I);xb.prototype.evaluate=function(){return this.ma};xb.prot",
+    "s.ma=a}q(xb,I);xb.prototype.evaluate=function(){return this.ma};xb.prot",
     "otype.toString=function(){return\"Number: \"+this.ma};function yb(a,b){",
     "I.call(this,a.f);this.aa=a;this.J=b;this.u=a.c();this.h=a.h;1==this.J.l",
     "ength&&(a=this.J[0],a.S||a.v!=zb||(a=a.P,\"*\"!=a.getName()&&(this.I={n",
-    "ame:a.getName(),G:null})))}r(yb,I);function Ab(){I.call(this,4)}r(Ab,I)",
+    "ame:a.getName(),G:null})))}q(yb,I);function Ab(){I.call(this,4)}q(Ab,I)",
     ";Ab.prototype.evaluate=function(a){var b=new G;a=a.m;9==a.nodeType?b.ad",
     "d(a):b.add(a.ownerDocument);return b};Ab.prototype.toString=function(){",
-    "return\"Root Helper Expression\"};function Bb(){I.call(this,4)}r(Bb,I);",
+    "return\"Root Helper Expression\"};function Bb(){I.call(this,4)}q(Bb,I);",
     "Bb.prototype.evaluate=function(a){var b=new G;b.add(a.m);return b};\nBb",
     ".prototype.toString=function(){return\"Context Helper Expression\"};fun",
     "ction Cb(a){return\"/\"==a||\"//\"==a}\nyb.prototype.evaluate=function(",
@@ -2226,7 +2232,7 @@
     "ion(){return this.b.length};P.prototype.toString=function(){return ra(t",
     "his.b,function(a,b){return a+J(b)},\"Predicates:\")};function Q(a,b,c,d",
     "){I.call(this,4);this.v=a;this.P=b;this.b=c||new P([]);this.S=!!d;b=thi",
-    "s.b.w();a.va&&b&&(this.I={name:b.name,G:b.G});this.u=this.b.c()}r(Q,I);",
+    "s.b.w();a.va&&b&&(this.I={name:b.name,G:b.G});this.u=this.b.c()}q(Q,I);",
     "\nQ.prototype.evaluate=function(a){var b=a.m,c=this.w(),d=null,e=null,f",
     "=0;c&&(d=c.name,e=c.G?M(c.G,a):null,f=1);if(this.S)if(this.c()||this.v!",
     "=Fb)if(b=(new Q(Gb,new H(\"node\"))).evaluate(a).iterator(),c=b.next())",
@@ -2260,15 +2266,15 @@
     "b)&&c.add(b);return c},!1),Eb=R(\"preceding\",function(a,b,c,d){var e=n",
     "ew G,f=[];do f.unshift(b);while(b=b.parentNode);for(var g=1,k=f.length;",
     "g<k;g++){var u=[];for(b=f[g];b=b.previousSibling;)u.unshift(b);for(var ",
-    "D=0,q=u.length;D<q;D++)b=u[D],Za(b,c,d)&&a.matches(b)&&e.add(b),e=$a(a,",
+    "D=0,r=u.length;D<r;D++)b=u[D],Za(b,c,d)&&a.matches(b)&&e.add(b),e=$a(a,",
     "b,c,d,e)}return e},!0,!0);\nR(\"preceding-sibling\",function(a,b){for(v",
     "ar c=new G;b=b.previousSibling;)a.matches(b)&&c.unshift(b);return c},!0",
     ");var Kb=R(\"self\",function(a,b){var c=new G;a.matches(b)&&c.add(b);re",
     "turn c},!1);function Lb(a){I.call(this,1);this.$=a;this.u=a.c();this.h=",
-    "a.h}r(Lb,I);Lb.prototype.evaluate=function(a){return-K(this.$,a)};Lb.pr",
+    "a.h}q(Lb,I);Lb.prototype.evaluate=function(a){return-K(this.$,a)};Lb.pr",
     "ototype.toString=function(){return\"Unary Expression: -\"+J(this.$)};fu",
     "nction Mb(a){I.call(this,4);this.O=a;hb(this,sa(this.O,function(a){retu",
-    "rn a.c()}));ib(this,sa(this.O,function(a){return a.h}))}r(Mb,I);Mb.prot",
+    "rn a.c()}));ib(this,sa(this.O,function(a){return a.h}))}q(Mb,I);Mb.prot",
     "otype.evaluate=function(a){var b=new G;w(this.O,function(c){c=c.evaluat",
     "e(a);if(!(c instanceof G))throw Error(\"Path expression must evaluate t",
     "o NodeSet.\");b=db(b,c)});return b};Mb.prototype.toString=function(){re",
@@ -2357,14 +2363,14 @@
     "rn a[b]||null}}();\nU.o=function(a,b,c){var d=z(a);if(!d.documentElemen",
     "t)return null;try{for(var e=d.createNSResolver?d.createNSResolver(d.doc",
     "umentElement):U.X,f={},g=d.getElementsByTagName(\"*\"),k=0;k<g.length;+",
-    "+k){var u=g[k],D=u.namespaceURI;if(D&&!f[D]){var q=u.lookupPrefix(D);if",
-    "(!q)var A=D.match(\".*/(\\\\w+)/?$\"),q=A?A[1]:\"xhtml\";f[D]=q}}var L=",
+    "+k){var u=g[k],D=u.namespaceURI;if(D&&!f[D]){var r=u.lookupPrefix(D);if",
+    "(!r)var A=D.match(\".*/(\\\\w+)/?$\"),r=A?A[1]:\"xhtml\";f[D]=r}}var L=",
     "{},W;for(W in f)L[f[W]]=W;e=function(a){return L[a]||null};try{return d",
-    ".evaluate(b,a,e,c,null)}catch(Ga){if(\"TypeError\"===Ga.name)return e=d",
+    ".evaluate(b,a,e,c,null)}catch(Fa){if(\"TypeError\"===Fa.name)return e=d",
     ".createNSResolver?d.createNSResolver(d.documentElement):\nU.X,d.evaluat",
-    "e(b,a,e,c,null);throw Ga;}}catch(Ga){throw new t(32,\"Unable to locate ",
+    "e(b,a,e,c,null);throw Fa;}}catch(Fa){throw new t(32,\"Unable to locate ",
     "an element with the xpath expression \"+b+\" because of the following e",
-    "rror:\\n\"+Ga);}};U.Y=function(a,b){if(!a||1!=a.nodeType)throw new t(32",
+    "rror:\\n\"+Fa);}};U.Y=function(a,b){if(!a||1!=a.nodeType)throw new t(32",
     ",'The result of the xpath expression \"'+b+'\" is: '+a+\". It should be",
     " an element.\");};\nU.A=function(a,b){var c=function(){var c=U.o(b,a,9)",
     ";return c?c.singleNodeValue||null:b.selectSingleNode?(c=z(b),c.setPrope",
@@ -2440,116 +2446,118 @@
     "n!!f.ba&&0<f.rect.width&&0<f.rect.height&&ec(f.ba,b,c);if(C(a,\"INPUT\"",
     ")&&\"hidden\"==a.type.toLowerCase()||C(a,\"NOSCRIPT\"))return!1;f=X(a,",
     "\"visibility\");return\"collapse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!=ic(a",
-    "))&&d(a)?!e(a):!1}\nfunction jc(a){var b=bc?function(c){if(\"none\"==X(",
-    "c,\"display\"))return!1;do{var d=c.parentNode;if(c.getDestinationInsert",
-    "ionPoints){var e=c.getDestinationInsertionPoints();0<e.length&&(d=e[e.l",
-    "ength-1])}if(d instanceof ShadowRoot)return!0;!d||9!=d.nodeType&&11!=d.",
-    "nodeType||(d=null)}while(a&&1!=a.nodeType);return!d||b(d)}:function(a){",
-    "if(\"none\"==X(a,\"display\"))return!1;a=cc(a);return!a||b(a)};return e",
-    "c(a,!1,b)}var Y=\"hidden\";\nfunction gc(a){function b(a){function b(a)",
-    "{return a==g?!0:0==X(a,\"display\").lastIndexOf(\"inline\",0)||\"absolu",
-    "te\"==c&&\"static\"==X(a,\"position\")?!1:!0}var c=X(a,\"position\");if",
-    "(\"fixed\"==c)return D=!0,a==g?null:g;for(a=cc(a);a&&!b(a);)a=cc(a);ret",
-    "urn a}function c(a){var b=a;if(\"visible\"==u)if(a==g&&k)b=k;else if(a=",
-    "=k)return{x:\"visible\",y:\"visible\"};b={x:X(b,\"overflow-x\"),y:X(b,",
-    "\"overflow-y\")};a==g&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible",
-    "\"==b.y?\"auto\":b.y);return b}function d(a){if(a==g){var b=(new za(f))",
-    ".C;\na=b.scrollingElement?b.scrollingElement:b.body||b.documentElement;",
-    "b=b.parentWindow||b.defaultView;a=new x(b.pageXOffset||a.scrollLeft,b.p",
-    "ageYOffset||a.scrollTop)}else a=new x(a.scrollLeft,a.scrollTop);return ",
-    "a}var e=kc(a);var f=z(a),g=f.documentElement,k=f.body,u=X(g,\"overflow",
-    "\"),D;for(a=b(a);a;a=b(a)){var q=c(a);if(\"visible\"!=q.x||\"visible\"!",
-    "=q.y){var A=fc(a);if(0==A.width||0==A.height)return Y;var L=e.right<A.l",
-    "eft,W=e.bottom<A.top;if(L&&\"hidden\"==q.x||W&&\"hidden\"==q.y)return Y",
-    ";if(L&&\"visible\"!=q.x||\nW&&\"visible\"!=q.y){L=d(a);W=e.bottom<A.top",
-    "-L.y;if(e.right<A.left-L.x&&\"visible\"!=q.x||W&&\"visible\"!=q.x)retur",
-    "n Y;e=gc(a);return e==Y?Y:\"scroll\"}L=e.left>=A.left+A.width;A=e.top>=",
-    "A.top+A.height;if(L&&\"hidden\"==q.x||A&&\"hidden\"==q.y)return Y;if(L&",
-    "&\"visible\"!=q.x||A&&\"visible\"!=q.y){if(D&&(q=d(a),e.left>=g.scrollW",
-    "idth-q.x||e.right>=g.scrollHeight-q.y))return Y;e=gc(a);return e==Y?Y:",
-    "\"scroll\"}}}return\"none\"}\nfunction fc(a){var b=hc(a);if(b)return b.",
-    "rect;if(C(a,\"HTML\"))return a=z(a),a=((a?a.parentWindow||a.defaultView",
-    ":window)||window).document,a=\"CSS1Compat\"==a.compatMode?a.documentEle",
-    "ment:a.body,a=new ya(a.clientWidth,a.clientHeight),new V(0,0,a.width,a.",
-    "height);try{var c=a.getBoundingClientRect()}catch(d){return new V(0,0,0",
-    ",0)}return new V(c.left,c.top,c.right-c.left,c.bottom-c.top)}\nfunction",
-    " hc(a){var b=C(a,\"MAP\");if(!b&&!C(a,\"AREA\"))return null;var c=b?a:C",
-    "(a.parentNode,\"MAP\")?a.parentNode:null,d=null,e=null;c&&c.name&&(d=U.",
-    "A('/descendant::*[@usemap = \"#'+c.name+'\"]',z(c)))&&(e=fc(d),b||\"def",
-    "ault\"==a.shape.toLowerCase()||(a=lc(a),b=Math.min(Math.max(a.left,0),e",
-    ".width),c=Math.min(Math.max(a.top,0),e.height),e=new V(b+e.left,c+e.top",
-    ",Math.min(a.width,e.width-b),Math.min(a.height,e.height-c))));return{ba",
-    ":d,rect:e||new V(0,0,0,0)}}\nfunction lc(a){var b=a.shape.toLowerCase()",
-    ";a=a.coords.split(\",\");if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1]",
-    ";return new V(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.length)return b",
-    "=a[2],new V(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.length){for(var ",
-    "b=a[0],c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.m",
-    "ax(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new V(b,c,d",
-    "-b,e-c)}return new V(0,0,0,0)}function kc(a){a=fc(a);return new ac(a.to",
-    "p,a.left+a.width,a.top+a.height,a.left)}\nfunction mc(a){return a.repla",
-    "ce(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g,\"\")}function nc(a){var b=[];bc?oc(a",
-    ",b):pc(a,b);var c=b;a=c.length;for(var b=Array(a),c=m(c)?c.split(\"\"):",
-    "c,d=0;d<a;d++)d in c&&(b[d]=mc.call(void 0,c[d]));return mc(b.join(\"",
-    "\\n\")).replace(/\\xa0/g,\" \")}\nfunction qc(a,b,c){if(C(a,\"BR\"))b.p",
-    "ush(\"\");else{var d=C(a,\"TD\"),e=X(a,\"display\"),f=!d&&!(0<=pa(rc,e)",
-    "),g=l(a.previousElementSibling)?a.previousElementSibling:Ca(a.previousS",
-    "ibling),g=g?X(g,\"display\"):\"\",k=X(a,\"float\")||X(a,\"cssFloat\")||",
-    "X(a,\"styleFloat\");!f||\"run-in\"==g&&\"none\"==k||/^[\\s\\xa0]*$/.tes",
-    "t(b[b.length-1]||\"\")||b.push(\"\");var u=jc(a),D=null,q=null;u&&(D=X(",
-    "a,\"white-space\"),q=X(a,\"text-transform\"));w(a.childNodes,function(a",
-    "){c(a,b,u,D,q)});a=b[b.length-1]||\"\";!d&&\"table-cell\"!=e||!a||ma(a)",
-    "||(b[b.length-\n1]+=\" \");f&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&",
-    "b.push(\"\")}}function pc(a,b){qc(a,b,function(a,b,e,f,g){3==a.nodeType",
-    "&&e?sc(a,b,f,g):C(a)&&pc(a,b)})}var rc=\"inline inline-block inline-tab",
-    "le none table-cell table-column table-column-group\".split(\" \");\nfun",
-    "ction sc(a,b,c,d){a=a.nodeValue.replace(/[\\u200b\\u200e\\u200f]/g,\"\"",
-    ");a=a.replace(/(\\r\\n|\\r|\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap\"",
-    "==c)a=a.replace(/\\n/g,\" \");a=\"pre\"==c||\"pre-wrap\"==c?a.replace(/",
-    "[ \\f\\t\\v\\u2028\\u2029]/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u20",
-    "28\\u2029]+/g,\" \");\"capitalize\"==d?a=a.replace(/(^|\\s)(\\S)/g,func",
-    "tion(a,b,c){return b+c.toUpperCase()}):\"uppercase\"==d?a=a.toUpperCase",
-    "():\"lowercase\"==d&&(a=a.toLowerCase());c=b.pop()||\"\";ma(c)&&0==a.la",
-    "stIndexOf(\" \",0)&&(a=a.substr(1));b.push(c+a)}\nfunction ic(a){var b=",
-    "1,c=X(a,\"opacity\");c&&(b=Number(c));(a=cc(a))&&(b*=ic(a));return b}\n",
-    "function tc(a,b,c,d,e){var f;if(3==a.nodeType&&c)sc(a,b,d,e);else if(C(",
-    "a))if(C(a,\"CONTENT\")){for(f=a;f.parentNode;)f=f.parentNode;f instance",
-    "of ShadowRoot?w(a.getDistributedNodes(),function(a){tc(a,b,c,d,e)}):oc(",
-    "a,b)}else if(C(a,\"SHADOW\")){for(f=a;f.parentNode;)f=f.parentNode;if(f",
-    " instanceof ShadowRoot&&(a=f))for(a=a.olderShadowRoot;a;)w(a.childNodes",
-    ",function(a){tc(a,b,c,d,e)}),a=a.olderShadowRoot}else oc(a,b)}\nfunctio",
-    "n oc(a,b){a.shadowRoot&&w(a.shadowRoot.childNodes,function(a){tc(a,b,!0",
-    ",null,null)});qc(a,b,function(a,b,e,f,g){var c=null;1==a.nodeType?c=a:3",
-    "==a.nodeType&&(c=a);null!=c&&c.getDestinationInsertionPoints&&0<c.getDe",
-    "stinationInsertionPoints().length||tc(a,b,e,f,g)})};var uc={K:function(",
-    "a,b){return!(!a.querySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)}",
-    ",A:function(a,b){var c=y(b),d=m(a)?c.C.getElementById(a):a;return d?Ra(",
-    "d,\"id\")==a&&Da(b,d)?d:ua(B(c,\"*\"),function(c){return Ra(c,\"id\")==",
-    "a&&Da(b,c)}):null},l:function(a,b){if(!a)return[];if(uc.K(b,a))try{retu",
-    "rn b.querySelectorAll(\"#\"+uc.na(a))}catch(c){return[]}b=B(y(b),\"*\",",
-    "null,b);return qa(b,function(b){return Ra(b,\"id\")==a})},na:function(a",
-    "){return a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[\\]\\(",
-    "\\)])/g,\"\\\\$1\")}};var Z={},vc={};Z.ja=function(a,b,c){try{var d=Ka.",
-    "l(\"a\",b)}catch(e){d=B(y(b),\"A\",null,b)}return ua(d,function(b){b=nc",
-    "(b);return c&&-1!=b.indexOf(a)||b==a})};Z.ea=function(a,b,c){try{var d=",
-    "Ka.l(\"a\",b)}catch(e){d=B(y(b),\"A\",null,b)}return qa(d,function(b){b",
-    "=nc(b);return c&&-1!=b.indexOf(a)||b==a})};Z.A=function(a,b){return Z.j",
-    "a(a,b,!1)};Z.l=function(a,b){return Z.ea(a,b,!1)};vc.A=function(a,b){re",
-    "turn Z.ja(a,b,!0)};vc.l=function(a,b){return Z.ea(a,b,!0)};var wc={A:fu",
-    "nction(a,b){if(\"\"===a)throw new t(32,'Unable to locate an element wit",
-    "h the tagName \"\"');return b.getElementsByTagName(a)[0]||null},l:funct",
-    "ion(a,b){if(\"\"===a)throw new t(32,'Unable to locate an element with t",
-    "he tagName \"\"');return b.getElementsByTagName(a)}};var xc={className:",
-    "Ja,\"class name\":Ja,css:Ka,\"css selector\":Ka,id:uc,linkText:Z,\"link",
-    " text\":Z,name:{A:function(a,b){b=B(y(b),\"*\",null,b);return ua(b,func",
-    "tion(b){return Ra(b,\"name\")==a})},l:function(a,b){b=B(y(b),\"*\",null",
-    ",b);return qa(b,function(b){return Ra(b,\"name\")==a})}},partialLinkTex",
-    "t:vc,\"partial link text\":vc,tagName:wc,\"tag name\":wc,xpath:U};ba(\"",
-    "_\",function(a,b){a:{for(c in a)if(a.hasOwnProperty(c))break a;var c=nu",
-    "ll}if(c){var d=xc[c];if(d&&p(d.l))return d.l(a[c],b||ja.document)}throw",
-    " Error(\"Unsupported locator strategy: \"+c);});; return this._.apply(n",
-    "ull,arguments);}.apply({navigator:typeof window!='undefined'?window.nav",
-    "igator:null,document:typeof window!='undefined'?window.document:null}, ",
-    "arguments);}",
+    "))&&d(a)?!e(a):!1}\nfunction jc(a){function b(a){if(C(a)&&\"none\"==X(a",
+    ",\"display\"))return!1;var c;(c=a.parentNode)&&c.shadowRoot&&void 0!==a",
+    ".assignedSlot?c=a.assignedSlot?a.assignedSlot.parentNode:null:a.getDest",
+    "inationInsertionPoints&&(a=a.getDestinationInsertionPoints(),0<a.length",
+    "&&(c=a[a.length-1]));return bc&&c instanceof ShadowRoot||c&&(9==c.nodeT",
+    "ype||11==c.nodeType)?!0:!!c&&b(c)}return ec(a,!1,b)}var Y=\"hidden\";\n",
+    "function gc(a){function b(a){function b(a){return a==g?!0:0==X(a,\"disp",
+    "lay\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"static\"==X(a,\"po",
+    "sition\")?!1:!0}var c=X(a,\"position\");if(\"fixed\"==c)return D=!0,a==",
+    "g?null:g;for(a=cc(a);a&&!b(a);)a=cc(a);return a}function c(a){var b=a;i",
+    "f(\"visible\"==u)if(a==g&&k)b=k;else if(a==k)return{x:\"visible\",y:\"v",
+    "isible\"};b={x:X(b,\"overflow-x\"),y:X(b,\"overflow-y\")};a==g&&(b.x=\"",
+    "visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);return b",
+    "}function d(a){if(a==g){var b=(new za(f)).C;\na=b.scrollingElement?b.sc",
+    "rollingElement:b.body||b.documentElement;b=b.parentWindow||b.defaultVie",
+    "w;a=new x(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}else ",
+    "a=new x(a.scrollLeft,a.scrollTop);return a}var e=kc(a);var f=z(a),g=f.d",
+    "ocumentElement,k=f.body,u=X(g,\"overflow\"),D;for(a=b(a);a;a=b(a)){var ",
+    "r=c(a);if(\"visible\"!=r.x||\"visible\"!=r.y){var A=fc(a);if(0==A.width",
+    "||0==A.height)return Y;var L=e.right<A.left,W=e.bottom<A.top;if(L&&\"hi",
+    "dden\"==r.x||W&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!=r.x||\nW&&",
+    "\"visible\"!=r.y){L=d(a);W=e.bottom<A.top-L.y;if(e.right<A.left-L.x&&\"",
+    "visible\"!=r.x||W&&\"visible\"!=r.x)return Y;e=gc(a);return e==Y?Y:\"sc",
+    "roll\"}L=e.left>=A.left+A.width;A=e.top>=A.top+A.height;if(L&&\"hidden",
+    "\"==r.x||A&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!=r.x||A&&\"visib",
+    "le\"!=r.y){if(D&&(r=d(a),e.left>=g.scrollWidth-r.x||e.right>=g.scrollHe",
+    "ight-r.y))return Y;e=gc(a);return e==Y?Y:\"scroll\"}}}return\"none\"}\n",
+    "function fc(a){var b=hc(a);if(b)return b.rect;if(C(a,\"HTML\"))return a",
+    "=z(a),a=((a?a.parentWindow||a.defaultView:window)||window).document,a=",
+    "\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=new ya(a.client",
+    "Width,a.clientHeight),new V(0,0,a.width,a.height);try{var c=a.getBoundi",
+    "ngClientRect()}catch(d){return new V(0,0,0,0)}return new V(c.left,c.top",
+    ",c.right-c.left,c.bottom-c.top)}\nfunction hc(a){var b=C(a,\"MAP\");if(",
+    "!b&&!C(a,\"AREA\"))return null;var c=b?a:C(a.parentNode,\"MAP\")?a.pare",
+    "ntNode:null,d=null,e=null;c&&c.name&&(d=U.A('/descendant::*[@usemap = ",
+    "\"#'+c.name+'\"]',z(c)))&&(e=fc(d),b||\"default\"==a.shape.toLowerCase(",
+    ")||(a=lc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.min(Math.max(",
+    "a.top,0),e.height),e=new V(b+e.left,c+e.top,Math.min(a.width,e.width-b)",
+    ",Math.min(a.height,e.height-c))));return{ba:d,rect:e||new V(0,0,0,0)}}",
+    "\nfunction lc(a){var b=a.shape.toLowerCase();a=a.coords.split(\",\");if",
+    "(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new V(b,c,a[2]-b,a[",
+    "3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new V(a[0]-b,a[1]-b,2",
+    "*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f",
+    "+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f",
+    "+1]),e=Math.max(e,a[f+1]);return new V(b,c,d-b,e-c)}return new V(0,0,0,",
+    "0)}function kc(a){a=fc(a);return new ac(a.top,a.left+a.width,a.top+a.he",
+    "ight,a.left)}\nfunction mc(a){return a.replace(/^[^\\S\\xa0]+|[^\\S\\xa",
+    "0]+$/g,\"\")}function nc(a){var b=[];bc?oc(a,b):pc(a,b);var c=b;a=c.len",
+    "gth;for(var b=Array(a),c=m(c)?c.split(\"\"):c,d=0;d<a;d++)d in c&&(b[d]",
+    "=mc.call(void 0,c[d]));return mc(b.join(\"\\n\")).replace(/\\xa0/g,\" ",
+    "\")}\nfunction qc(a,b,c){if(C(a,\"BR\"))b.push(\"\");else{var d=C(a,\"T",
+    "D\"),e=X(a,\"display\"),f=!d&&!(0<=pa(rc,e)),g=l(a.previousElementSibli",
+    "ng)?a.previousElementSibling:Ca(a.previousSibling),g=g?X(g,\"display\")",
+    ":\"\",k=X(a,\"float\")||X(a,\"cssFloat\")||X(a,\"styleFloat\");!f||\"ru",
+    "n-in\"==g&&\"none\"==k||/^[\\s\\xa0]*$/.test(b[b.length-1]||\"\")||b.pu",
+    "sh(\"\");var u=jc(a),D=null,r=null;u&&(D=X(a,\"white-space\"),r=X(a,\"t",
+    "ext-transform\"));w(a.childNodes,function(a){c(a,b,u,D,r)});a=b[b.lengt",
+    "h-1]||\"\";!d&&\"table-cell\"!=e||!a||ma(a)||(b[b.length-\n1]+=\" \");f",
+    "&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(\"\")}}function pc(a,",
+    "b){qc(a,b,function(a,b,e,f,g){3==a.nodeType&&e?sc(a,b,f,g):C(a)&&pc(a,b",
+    ")})}var rc=\"inline inline-block inline-table none table-cell table-col",
+    "umn table-column-group\".split(\" \");\nfunction sc(a,b,c,d){a=a.nodeVa",
+    "lue.replace(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.replace(/(\\r\\n|\\r|",
+    "\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.replace(/\\n/g,\" ",
+    "\");a=\"pre\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u2028\\u2029]",
+    "/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u2029]+/g,\" \");\"cap",
+    "italize\"==d?a=a.replace(/(^|\\s)(\\S)/g,function(a,b,c){return b+c.toU",
+    "pperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"==d&&(a=a.",
+    "toLowerCase());c=b.pop()||\"\";ma(c)&&0==a.lastIndexOf(\" \",0)&&(a=a.s",
+    "ubstr(1));b.push(c+a)}\nfunction ic(a){var b=1,c=X(a,\"opacity\");c&&(b",
+    "=Number(c));(a=cc(a))&&(b*=ic(a));return b}\nfunction tc(a,b,c,d,e){var",
+    " f;if(3==a.nodeType&&c)sc(a,b,d,e);else if(C(a))if(C(a,\"CONTENT\")||C(",
+    "a,\"SLOT\")){for(f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRo",
+    "ot?(a=C(a,\"CONTENT\")?a.getDistributedNodes():a.assignedNodes(),w(a,fu",
+    "nction(a){tc(a,b,c,d,e)})):oc(a,b)}else if(C(a,\"SHADOW\")){for(f=a;f.p",
+    "arentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.old",
+    "erShadowRoot;a;)w(a.childNodes,function(a){tc(a,b,c,d,e)}),a=a.olderSha",
+    "dowRoot}else oc(a,b)}\nfunction oc(a,b){a.shadowRoot&&w(a.shadowRoot.ch",
+    "ildNodes,function(a){tc(a,b,!0,null,null)});qc(a,b,function(a,b,e,f,g){",
+    "var c=null;1==a.nodeType?c=a:3==a.nodeType&&(c=a);null!=c&&(null!=c.ass",
+    "ignedSlot||c.getDestinationInsertionPoints&&0<c.getDestinationInsertion",
+    "Points().length)||tc(a,b,e,f,g)})};var uc={K:function(a,b){return!(!a.q",
+    "uerySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)},A:function(a,b){",
+    "var c=y(b),d=m(a)?c.C.getElementById(a):a;return d?Ra(d,\"id\")==a&&b!=",
+    "d&&Da(b,d)?d:ua(B(c,\"*\"),function(c){return Ra(c,\"id\")==a&&b!=c&&Da",
+    "(b,c)}):null},l:function(a,b){if(!a)return[];if(uc.K(b,a))try{return b.",
+    "querySelectorAll(\"#\"+uc.na(a))}catch(c){return[]}b=B(y(b),\"*\",null,",
+    "b);return qa(b,function(b){return Ra(b,\"id\")==a})},na:function(a){ret",
+    "urn a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[\\]\\(\\)])/g",
+    ",\n\"\\\\$1\")}};var Z={},vc={};Z.ja=function(a,b,c){try{var d=Ka.l(\"a",
+    "\",b)}catch(e){d=B(y(b),\"A\",null,b)}return ua(d,function(b){b=nc(b);b",
+    "=b.replace(/^[\\s]+|[\\s]+$/g,\"\");return c&&-1!=b.indexOf(a)||b==a})}",
+    ";Z.ea=function(a,b,c){try{var d=Ka.l(\"a\",b)}catch(e){d=B(y(b),\"A\",n",
+    "ull,b)}return qa(d,function(b){b=nc(b);b=b.replace(/^[\\s]+|[\\s]+$/g,",
+    "\"\");return c&&-1!=b.indexOf(a)||b==a})};Z.A=function(a,b){return Z.ja",
+    "(a,b,!1)};Z.l=function(a,b){return Z.ea(a,b,!1)};vc.A=function(a,b){ret",
+    "urn Z.ja(a,b,!0)};\nvc.l=function(a,b){return Z.ea(a,b,!0)};var wc={A:f",
+    "unction(a,b){if(\"\"===a)throw new t(32,'Unable to locate an element wi",
+    "th the tagName \"\"');return b.getElementsByTagName(a)[0]||null},l:func",
+    "tion(a,b){if(\"\"===a)throw new t(32,'Unable to locate an element with ",
+    "the tagName \"\"');return b.getElementsByTagName(a)}};var xc={className",
+    ":Ja,\"class name\":Ja,css:Ka,\"css selector\":Ka,id:uc,linkText:Z,\"lin",
+    "k text\":Z,name:{A:function(a,b){b=B(y(b),\"*\",null,b);return ua(b,fun",
+    "ction(b){return Ra(b,\"name\")==a})},l:function(a,b){b=B(y(b),\"*\",nul",
+    "l,b);return qa(b,function(b){return Ra(b,\"name\")==a})}},partialLinkTe",
+    "xt:vc,\"partial link text\":vc,tagName:wc,\"tag name\":wc,xpath:U};ba(",
+    "\"_\",function(a,b){a:{for(c in a)if(a.hasOwnProperty(c))break a;var c=",
+    "null}if(c){var d=xc[c];if(d&&p(d.l))return d.l(a[c],b||ja.document)}thr",
+    "ow Error(\"Unsupported locator strategy: \"+c);});; return this._.apply",
+    "(null,arguments);}.apply({navigator:typeof window!='undefined'?window.n",
+    "avigator:null,document:typeof window!='undefined'?window.document:null}",
+    ", arguments);}",
     NULL
 };
 
@@ -3209,13 +3217,13 @@
     "sion not created\";w[10]=\"stale element reference\";w[21]=\"timeout\";",
     "w[25]=\"unable to set cookie\";w[26]=\"unexpected alert open\";w[13]=wa",
     ";w[9]=\"unknown command\";va.prototype.toString=function(){return this.",
-    "name+\": \"+this.message};function y(a,b){this.x=k(a)?a:0;this.y=k(b)?b",
-    ":0}h=y.prototype;h.clone=function(){return new y(this.x,this.y)};h.toSt",
+    "name+\": \"+this.message};function x(a,b){this.x=k(a)?a:0;this.y=k(b)?b",
+    ":0}h=x.prototype;h.clone=function(){return new x(this.x,this.y)};h.toSt",
     "ring=function(){return\"(\"+this.x+\", \"+this.y+\")\"};h.ceil=function",
     "(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this};h.flo",
     "or=function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);retur",
     "n this};h.round=function(){this.x=Math.round(this.x);this.y=Math.round(",
-    "this.y);return this};\nh.translate=function(a,b){a instanceof y?(this.x",
+    "this.y);return this};\nh.translate=function(a,b){a instanceof x?(this.x",
     "+=a.x,this.y+=a.y):(this.x+=Number(a),n(b)&&(this.y+=b));return this};h",
     ".scale=function(a,b){b=n(b)?b:a;this.x*=a;this.y*=b;return this};functi",
     "on xa(a,b){this.width=a;this.height=b}h=xa.prototype;h.clone=function()",
@@ -3597,7 +3605,7 @@
     ".documentElement):Jb,e={},f=c.getElementsByTagName(\"*\"),g=0;g<f.lengt",
     "h;++g){var l=f[g],r=l.namespaceURI;if(r&&!e[r]){var J=l.lookupPrefix(r)",
     ";if(!J)var t=r.match(\".*/(\\\\w+)/?$\"),J=t?t[1]:\"xhtml\";e[r]=J}}var",
-    " x={},E;for(E in e)x[e[E]]=E;d=function(a){return x[a]||null};try{retur",
+    " y={},E;for(E in e)y[e[E]]=E;d=function(a){return y[a]||null};try{retur",
     "n c.evaluate(b,a,d,9,null)}catch(N){if(\"TypeError\"===N.name)return d=",
     "c.createNSResolver?c.createNSResolver(c.documentElement):\nJb,c.evaluat",
     "e(b,a,d,9,null);throw N;}}catch(N){throw new va(32,\"Unable to locate a",
@@ -3624,14 +3632,14 @@
     "eft);return this};h.round=function(){this.top=Math.round(this.top);this",
     ".right=Math.round(this.right);this.bottom=Math.round(this.bottom);this.",
     "left=Math.round(this.left);return this};h.translate=function(a,b){a ins",
-    "tanceof y?(this.left+=a.x,this.right+=a.x,this.top+=a.y,this.bottom+=a.",
+    "tanceof x?(this.left+=a.x,this.right+=a.x,this.top+=a.y,this.bottom+=a.",
     "y):(this.left+=a,this.right+=a,n(b)&&(this.top+=b,this.bottom+=b));retu",
     "rn this};\nh.scale=function(a,b){b=n(b)?b:a;this.left*=a;this.right*=a;",
     "this.top*=b;this.bottom*=b;return this};function X(a,b,c,d){this.left=a",
     ";this.top=b;this.width=c;this.height=d}h=X.prototype;h.clone=function()",
     "{return new X(this.left,this.top,this.width,this.height)};h.toString=fu",
     "nction(){return\"(\"+this.left+\", \"+this.top+\" - \"+this.width+\"w x",
-    " \"+this.height+\"h)\"};h.contains=function(a){return a instanceof y?a.",
+    " \"+this.height+\"h)\"};h.contains=function(a){return a instanceof x?a.",
     "x>=this.left&&a.x<=this.left+this.width&&a.y>=this.top&&a.y<=this.top+t",
     "his.height:this.left<=a.left&&this.left+this.width>=a.left+a.width&&thi",
     "s.top<=a.top&&this.top+this.height>=a.top+a.height};\nh.ceil=function()",
@@ -3642,7 +3650,7 @@
     ".height);return this};h.round=function(){this.left=Math.round(this.left",
     ");this.top=Math.round(this.top);this.width=Math.round(this.width);this.",
     "height=Math.round(this.height);return this};\nh.translate=function(a,b)",
-    "{a instanceof y?(this.left+=a.x,this.top+=a.y):(this.left+=a,n(b)&&(thi",
+    "{a instanceof x?(this.left+=a.x,this.top+=a.y):(this.left+=a,n(b)&&(thi",
     "s.top+=b));return this};h.scale=function(a,b){b=n(b)?b:a;this.left*=a;t",
     "his.width*=a;this.top*=b;this.height*=b;return this};var Nb=\"function",
     "\"===typeof ShadowRoot;function Ob(a){for(a=a.parentNode;a&&1!=a.nodeTy",
@@ -3683,16 +3691,16 @@
     "&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y)",
     ";return b}function d(a){if(a==g){var b=(new Fa(f)).H;\na=b.scrollingEle",
     "ment?b.scrollingElement:b.body||b.documentElement;b=b.parentWindow||b.d",
-    "efaultView;a=new y(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollT",
-    "op)}else a=new y(a.scrollLeft,a.scrollTop);return a}var e=Vb(a);var f=z",
+    "efaultView;a=new x(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollT",
+    "op)}else a=new x(a.scrollLeft,a.scrollTop);return a}var e=Vb(a);var f=z",
     "(a),g=f.documentElement,l=f.body,r=Y(g,\"overflow\"),J;for(a=b(a);a;a=b",
-    "(a)){var t=c(a);if(\"visible\"!=t.x||\"visible\"!=t.y){var x=Rb(a);if(0",
-    "==x.width||0==x.height)return Z;var E=e.right<x.left,N=e.bottom<x.top;i",
+    "(a)){var t=c(a);if(\"visible\"!=t.x||\"visible\"!=t.y){var y=Rb(a);if(0",
+    "==y.width||0==y.height)return Z;var E=e.right<y.left,N=e.bottom<y.top;i",
     "f(E&&\"hidden\"==t.x||N&&\"hidden\"==t.y)return Z;if(E&&\"visible\"!=t.",
-    "x||\nN&&\"visible\"!=t.y){E=d(a);N=e.bottom<x.top-E.y;if(e.right<x.left",
+    "x||\nN&&\"visible\"!=t.y){E=d(a);N=e.bottom<y.top-E.y;if(e.right<y.left",
     "-E.x&&\"visible\"!=t.x||N&&\"visible\"!=t.x)return Z;e=Sb(a);return e==",
-    "Z?Z:\"scroll\"}E=e.left>=x.left+x.width;x=e.top>=x.top+x.height;if(E&&",
-    "\"hidden\"==t.x||x&&\"hidden\"==t.y)return Z;if(E&&\"visible\"!=t.x||x&",
+    "Z?Z:\"scroll\"}E=e.left>=y.left+y.width;y=e.top>=y.top+y.height;if(E&&",
+    "\"hidden\"==t.x||y&&\"hidden\"==t.y)return Z;if(E&&\"visible\"!=t.x||y&",
     "&\"visible\"!=t.y){if(J&&(t=d(a),e.left>=g.scrollWidth-t.x||e.right>=g.",
     "scrollHeight-t.y))return Z;e=Sb(a);return e==Z?Z:\"scroll\"}}}return\"n",
     "one\"}\nfunction Rb(a){var b=Tb(a);if(b)return b.rect;if(A(a,\"HTML\"))",
@@ -3715,16 +3723,15 @@
     "a[f+1]),e=Math.max(e,a[f+1]);return new X(b,c,d-b,e-c)}return new X(0,0",
     ",0,0)}function Vb(a){a=Rb(a);return new Mb(a.top,a.left+a.width,a.top+a",
     ".height,a.left)}\nfunction Ub(a){var b=1,c=Y(a,\"opacity\");c&&(b=Numbe",
-    "r(c));(a=Ob(a))&&(b*=Ub(a));return b};ba(\"_\",function(a,b){var c=Nb?f",
-    "unction(b){if(\"none\"==Y(b,\"display\"))return!1;do{var d=b.parentNode",
-    ";if(b.getDestinationInsertionPoints){var f=b.getDestinationInsertionPoi",
-    "nts();0<f.length&&(d=f[f.length-1])}if(d instanceof ShadowRoot)return!0",
-    ";!d||9!=d.nodeType&&11!=d.nodeType||(d=null)}while(a&&1!=a.nodeType);re",
-    "turn!d||c(d)}:function(a){if(\"none\"==Y(a,\"display\"))return!1;a=Ob(a",
-    ");return!a||c(a)};return Qb(a,!!b,c)});; return this._.apply(null,argum",
-    "ents);}.apply({navigator:typeof window!='undefined'?window.navigator:nu",
-    "ll,document:typeof window!='undefined'?window.document:null}, arguments",
-    ");}",
+    "r(c));(a=Ob(a))&&(b*=Ub(a));return b};ba(\"_\",function(a,b){function c",
+    "(a){if(A(a)&&\"none\"==Y(a,\"display\"))return!1;var b;(b=a.parentNode)",
+    "&&b.shadowRoot&&void 0!==a.assignedSlot?b=a.assignedSlot?a.assignedSlot",
+    ".parentNode:null:a.getDestinationInsertionPoints&&(a=a.getDestinationIn",
+    "sertionPoints(),0<a.length&&(b=a[a.length-1]));return Nb&&b instanceof ",
+    "ShadowRoot||b&&(9==b.nodeType||11==b.nodeType)?!0:!!b&&c(b)}return Qb(a",
+    ",!!b,c)});; return this._.apply(null,arguments);}.apply({navigator:type",
+    "of window!='undefined'?window.navigator:null,document:typeof window!='u",
+    "ndefined'?window.document:null}, arguments);}",
     NULL
 };
 
@@ -4626,7 +4633,7 @@
     "().indexOf(\"native code\")?fa:ga;return ha.apply(null,arguments)}\nfun",
     "ction ia(a,b){var c=Array.prototype.slice.call(arguments,1);return func",
     "tion(){var b=c.slice();b.push.apply(b,arguments);return a.apply(this,b)",
-    "}}function r(a,b){function c(){}c.prototype=b.prototype;a.xa=b.prototyp",
+    "}}function q(a,b){function c(){}c.prototype=b.prototype;a.xa=b.prototyp",
     "e;a.prototype=new c;a.prototype.constructor=a;a.wa=function(a,c,f){for(",
     "var d=Array(arguments.length-2),e=2;e<arguments.length;e++)d[e-2]=argum",
     "ents[e];return b.prototype[c].apply(a,d)}};var ja=window;var ka;functio",
@@ -4701,20 +4708,20 @@
     "-F])([0-9a-fA-F])/,Aa=/^#(?:[0-9a-f]{3}){1,2}$/i,Ba=/^(?:rgba)?\\((\\d{",
     "1,3}),\\s?(\\d{1,3}),\\s?(\\d{1,3}),\\s?(0|1|0\\.\\d*)\\)$/i,Ca=/^(?:rg",
     "b)?\\((0|[1-9]\\d{0,2}),\\s?(0|[1-9]\\d{0,2}),\\s?(0|[1-9]\\d{0,2})\\)$",
-    "/i;function v(a,b){this.code=a;this.state=w[a]||Da;this.message=b||\"\"",
+    "/i;function v(a,b){this.code=a;this.state=w[a]||Ea;this.message=b||\"\"",
     ";a=this.state.replace(/((?:^|\\s+)[a-z])/g,function(a){return a.toUpper",
     "Case().replace(/^[\\s\\xa0]+/g,\"\")});b=a.length-5;if(0>b||a.indexOf(",
     "\"Error\",b)!=b)a+=\"Error\";this.name=a;a=Error(this.message);a.name=t",
-    "his.name;this.stack=a.stack||\"\"}r(v,Error);var Da=\"unknown error\",w",
-    "={15:\"element not selectable\",11:\"element not visible\"};w[31]=Da;w[",
-    "30]=Da;w[24]=\"invalid cookie domain\";w[29]=\"invalid element coordina",
+    "his.name;this.stack=a.stack||\"\"}q(v,Error);var Ea=\"unknown error\",w",
+    "={15:\"element not selectable\",11:\"element not visible\"};w[31]=Ea;w[",
+    "30]=Ea;w[24]=\"invalid cookie domain\";w[29]=\"invalid element coordina",
     "tes\";w[12]=\"invalid element state\";\nw[32]=\"invalid selector\";w[51",
     "]=\"invalid selector\";w[52]=\"invalid selector\";w[17]=\"javascript er",
     "ror\";w[405]=\"unsupported operation\";w[34]=\"move target out of bound",
     "s\";w[27]=\"no such alert\";w[7]=\"no such element\";w[8]=\"no such fra",
     "me\";w[23]=\"no such window\";w[28]=\"script timeout\";w[33]=\"session ",
     "not created\";w[10]=\"stale element reference\";w[21]=\"timeout\";w[25]",
-    "=\"unable to set cookie\";w[26]=\"unexpected alert open\";w[13]=Da;w[9]",
+    "=\"unable to set cookie\";w[26]=\"unexpected alert open\";w[13]=Ea;w[9]",
     "=\"unknown command\";v.prototype.toString=function(){return this.name+",
     "\": \"+this.message};function x(a,b){this.x=l(a)?a:0;this.y=l(b)?b:0}h=",
     "x.prototype;h.clone=function(){return new x(this.x,this.y)};h.toString=",
@@ -4850,7 +4857,7 @@
     "b(a,b,c){I.call(this,a.f);this.V=a;this.ca=b;this.ia=c;this.v=b.c()||c.",
     "c();this.h=b.h||c.h;this.V==jb&&(c.h||c.c()||4==c.f||0==c.f||!b.A()?b.h",
     "||b.c()||4==b.f||0==b.f||!c.A()||(this.I={name:c.A().name,G:b}):this.I=",
-    "{name:b.A().name,G:c})}r(ib,I);\nfunction kb(a,b,c,d,e){b=b.evaluate(d)",
+    "{name:b.A().name,G:c})}q(ib,I);\nfunction kb(a,b,c,d,e){b=b.evaluate(d)",
     ";c=c.evaluate(d);var f;if(b instanceof G&&c instanceof G){b=b.iterator(",
     ");for(d=b.next();d;d=b.next())for(e=c.iterator(),f=e.next();f;f=e.next(",
     "))if(a(F(d),F(f)))return!0;return!1}if(b instanceof G||c instanceof G){",
@@ -4880,7 +4887,7 @@
     "urn hb(a,c)&&hb(b,c)});N(\"or\",1,2,function(a,b,c){return hb(a,c)||hb(",
     "b,c)});function nb(a,b){if(b.s()&&4!=a.f)throw Error(\"Primary expressi",
     "on must evaluate to nodeset if filter has predicate(s).\");I.call(this,",
-    "a.f);this.ha=a;this.b=b;this.v=a.c();this.h=a.h}r(nb,I);nb.prototype.ev",
+    "a.f);this.ha=a;this.b=b;this.v=a.c();this.h=a.h}q(nb,I);nb.prototype.ev",
     "aluate=function(a){a=this.ha.evaluate(a);return ob(this.b,a)};nb.protot",
     "ype.toString=function(){var a=\"Filter:\"+J(this.ha);return a+=J(this.b",
     ")};function pb(a,b){if(b.length<a.fa)throw Error(\"Function \"+a.i+\" e",
@@ -4890,7 +4897,7 @@
     "b.f)throw Error(\"Argument \"+d+\" to function \"+a.i+\" is not of type",
     " Nodeset: \"+b);});I.call(this,a.f);this.L=a;this.R=b;fb(this,a.v||ra(b",
     ",function(a){return a.c()}));gb(this,a.pa&&!b.length||a.oa&&!!b.length|",
-    "|ra(b,function(a){return a.h}))}\nr(pb,I);pb.prototype.evaluate=functio",
+    "|ra(b,function(a){return a.h}))}\nq(pb,I);pb.prototype.evaluate=functio",
     "n(a){return this.L.o.apply(null,ua(a,this.R))};pb.prototype.toString=fu",
     "nction(){var a=\"Function: \"+this.L;if(this.R.length)var b=qa(this.R,f",
     "unction(a,b){return a+J(b)},\"Arguments:\"),a=a+J(b);return a};function",
@@ -4945,7 +4952,7 @@
     "rototype.getName=function(){return this.la};\nH.prototype.toString=func",
     "tion(){var a=\"Kind Test: \"+this.la;null===this.da||(a+=J(this.da));re",
     "turn a};function tb(a){I.call(this,3);this.ka=a.substring(1,a.length-1)",
-    "}r(tb,I);tb.prototype.evaluate=function(){return this.ka};tb.prototype.",
+    "}q(tb,I);tb.prototype.evaluate=function(){return this.ka};tb.prototype.",
     "toString=function(){return\"Literal: \"+this.ka};function ub(a,b){this.",
     "i=a.toLowerCase();a=\"*\"==this.i?\"*\":\"http://www.w3.org/1999/xhtml",
     "\";this.N=b?b.toLowerCase():a}ub.prototype.matches=function(a){var b=a.",
@@ -4955,14 +4962,14 @@
     "9/xhtml\")};ub.prototype.getName=function(){return this.i};\nub.prototy",
     "pe.toString=function(){return\"Name Test: \"+(\"http://www.w3.org/1999/",
     "xhtml\"==this.N?\"\":this.N+\":\")+this.i};function vb(a){I.call(this,1",
-    ");this.ma=a}r(vb,I);vb.prototype.evaluate=function(){return this.ma};vb",
+    ");this.ma=a}q(vb,I);vb.prototype.evaluate=function(){return this.ma};vb",
     ".prototype.toString=function(){return\"Number: \"+this.ma};function wb(",
     "a,b){I.call(this,a.f);this.aa=a;this.J=b;this.v=a.c();this.h=a.h;1==thi",
     "s.J.length&&(a=this.J[0],a.S||a.w!=xb||(a=a.P,\"*\"!=a.getName()&&(this",
-    ".I={name:a.getName(),G:null})))}r(wb,I);function yb(){I.call(this,4)}r(",
+    ".I={name:a.getName(),G:null})))}q(wb,I);function yb(){I.call(this,4)}q(",
     "yb,I);yb.prototype.evaluate=function(a){var b=new G;a=a.m;9==a.nodeType",
     "?b.add(a):b.add(a.ownerDocument);return b};yb.prototype.toString=functi",
-    "on(){return\"Root Helper Expression\"};function zb(){I.call(this,4)}r(z",
+    "on(){return\"Root Helper Expression\"};function zb(){I.call(this,4)}q(z",
     "b,I);zb.prototype.evaluate=function(a){var b=new G;b.add(a.m);return b}",
     ";\nzb.prototype.toString=function(){return\"Context Helper Expression\"",
     "};function Ab(a){return\"/\"==a||\"//\"==a}\nwb.prototype.evaluate=func",
@@ -4987,7 +4994,7 @@
     "=function(){return this.b.length};P.prototype.toString=function(){retur",
     "n qa(this.b,function(a,b){return a+J(b)},\"Predicates:\")};function Q(a",
     ",b,c,d){I.call(this,4);this.w=a;this.P=b;this.b=c||new P([]);this.S=!!d",
-    ";b=this.b.A();a.va&&b&&(this.I={name:b.name,G:b.G});this.v=this.b.c()}r",
+    ";b=this.b.A();a.va&&b&&(this.I={name:b.name,G:b.G});this.v=this.b.c()}q",
     "(Q,I);\nQ.prototype.evaluate=function(a){var b=a.m,c=this.A(),d=null,e=",
     "null,f=0;c&&(d=c.name,e=c.G?M(c.G,a):null,f=1);if(this.S)if(this.c()||t",
     "his.w!=Db)if(b=(new Q(Eb,new H(\"node\"))).evaluate(a).iterator(),c=b.n",
@@ -5021,15 +5028,15 @@
     "tches(b)&&c.add(b);return c},!1),Cb=R(\"preceding\",function(a,b,c,d){v",
     "ar e=new G,f=[];do f.unshift(b);while(b=b.parentNode);for(var g=1,k=f.l",
     "ength;g<k;g++){var u=[];for(b=f[g];b=b.previousSibling;)u.unshift(b);fo",
-    "r(var D=0,q=u.length;D<q;D++)b=u[D],Xa(b,c,d)&&a.matches(b)&&e.add(b),e",
+    "r(var D=0,r=u.length;D<r;D++)b=u[D],Xa(b,c,d)&&a.matches(b)&&e.add(b),e",
     "=Ya(a,b,c,d,e)}return e},!0,!0);\nR(\"preceding-sibling\",function(a,b)",
     "{for(var c=new G;b=b.previousSibling;)a.matches(b)&&c.unshift(b);return",
     " c},!0);var Ib=R(\"self\",function(a,b){var c=new G;a.matches(b)&&c.add",
     "(b);return c},!1);function Jb(a){I.call(this,1);this.$=a;this.v=a.c();t",
-    "his.h=a.h}r(Jb,I);Jb.prototype.evaluate=function(a){return-K(this.$,a)}",
+    "his.h=a.h}q(Jb,I);Jb.prototype.evaluate=function(a){return-K(this.$,a)}",
     ";Jb.prototype.toString=function(){return\"Unary Expression: -\"+J(this.",
     "$)};function Kb(a){I.call(this,4);this.O=a;fb(this,ra(this.O,function(a",
-    "){return a.c()}));gb(this,ra(this.O,function(a){return a.h}))}r(Kb,I);K",
+    "){return a.c()}));gb(this,ra(this.O,function(a){return a.h}))}q(Kb,I);K",
     "b.prototype.evaluate=function(a){var b=new G;t(this.O,function(c){c=c.e",
     "valuate(a);if(!(c instanceof G))throw Error(\"Path expression must eval",
     "uate to NodeSet.\");b=bb(b,c)});return b};Kb.prototype.toString=functio",
@@ -5118,14 +5125,14 @@
     "){return a[b]||null}}();\nU.o=function(a,b,c){var d=z(a);if(!d.document",
     "Element)return null;try{for(var e=d.createNSResolver?d.createNSResolver",
     "(d.documentElement):U.X,f={},g=d.getElementsByTagName(\"*\"),k=0;k<g.le",
-    "ngth;++k){var u=g[k],D=u.namespaceURI;if(D&&!f[D]){var q=u.lookupPrefix",
-    "(D);if(!q)var A=D.match(\".*/(\\\\w+)/?$\"),q=A?A[1]:\"xhtml\";f[D]=q}}",
+    "ngth;++k){var u=g[k],D=u.namespaceURI;if(D&&!f[D]){var r=u.lookupPrefix",
+    "(D);if(!r)var A=D.match(\".*/(\\\\w+)/?$\"),r=A?A[1]:\"xhtml\";f[D]=r}}",
     "var L={},W;for(W in f)L[f[W]]=W;e=function(a){return L[a]||null};try{re",
-    "turn d.evaluate(b,a,e,c,null)}catch(Ea){if(\"TypeError\"===Ea.name)retu",
+    "turn d.evaluate(b,a,e,c,null)}catch(Da){if(\"TypeError\"===Da.name)retu",
     "rn e=d.createNSResolver?d.createNSResolver(d.documentElement):\nU.X,d.e",
-    "valuate(b,a,e,c,null);throw Ea;}}catch(Ea){throw new v(32,\"Unable to l",
+    "valuate(b,a,e,c,null);throw Da;}}catch(Da){throw new v(32,\"Unable to l",
     "ocate an element with the xpath expression \"+b+\" because of the follo",
-    "wing error:\\n\"+Ea);}};U.Y=function(a,b){if(!a||1!=a.nodeType)throw ne",
+    "wing error:\\n\"+Da);}};U.Y=function(a,b){if(!a||1!=a.nodeType)throw ne",
     "w v(32,'The result of the xpath expression \"'+b+'\" is: '+a+\". It sho",
     "uld be an element.\");};\nU.u=function(a,b){var c=function(){var c=U.o(",
     "b,a,9);return c?c.singleNodeValue||null:b.selectSingleNode?(c=z(b),c.se",
@@ -5201,137 +5208,139 @@
     ")return!!f.ba&&0<f.rect.width&&0<f.rect.height&&cc(f.ba,b,c);if(C(a,\"I",
     "NPUT\")&&\"hidden\"==a.type.toLowerCase()||C(a,\"NOSCRIPT\"))return!1;f",
     "=X(a,\"visibility\");return\"collapse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!",
-    "=gc(a))&&d(a)?!e(a):!1}\nfunction hc(a){var b=$b?function(c){if(\"none",
-    "\"==X(c,\"display\"))return!1;do{var d=c.parentNode;if(c.getDestination",
-    "InsertionPoints){var e=c.getDestinationInsertionPoints();0<e.length&&(d",
-    "=e[e.length-1])}if(d instanceof ShadowRoot)return!0;!d||9!=d.nodeType&&",
-    "11!=d.nodeType||(d=null)}while(a&&1!=a.nodeType);return!d||b(d)}:functi",
-    "on(a){if(\"none\"==X(a,\"display\"))return!1;a=ac(a);return!a||b(a)};re",
-    "turn cc(a,!1,b)}var Y=\"hidden\";\nfunction ec(a){function b(a){functio",
-    "n b(a){return a==g?!0:0==X(a,\"display\").lastIndexOf(\"inline\",0)||\"",
-    "absolute\"==c&&\"static\"==X(a,\"position\")?!1:!0}var c=X(a,\"position",
-    "\");if(\"fixed\"==c)return D=!0,a==g?null:g;for(a=ac(a);a&&!b(a);)a=ac(",
-    "a);return a}function c(a){var b=a;if(\"visible\"==u)if(a==g&&k)b=k;else",
-    " if(a==k)return{x:\"visible\",y:\"visible\"};b={x:X(b,\"overflow-x\"),y",
-    ":X(b,\"overflow-y\")};a==g&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"vi",
-    "sible\"==b.y?\"auto\":b.y);return b}function d(a){if(a==g){var b=(new G",
-    "a(f)).C;\na=b.scrollingElement?b.scrollingElement:b.body||b.documentEle",
-    "ment;b=b.parentWindow||b.defaultView;a=new x(b.pageXOffset||a.scrollLef",
-    "t,b.pageYOffset||a.scrollTop)}else a=new x(a.scrollLeft,a.scrollTop);re",
-    "turn a}var e=ic(a);var f=z(a),g=f.documentElement,k=f.body,u=X(g,\"over",
-    "flow\"),D;for(a=b(a);a;a=b(a)){var q=c(a);if(\"visible\"!=q.x||\"visibl",
-    "e\"!=q.y){var A=dc(a);if(0==A.width||0==A.height)return Y;var L=e.right",
-    "<A.left,W=e.bottom<A.top;if(L&&\"hidden\"==q.x||W&&\"hidden\"==q.y)retu",
-    "rn Y;if(L&&\"visible\"!=q.x||\nW&&\"visible\"!=q.y){L=d(a);W=e.bottom<A",
-    ".top-L.y;if(e.right<A.left-L.x&&\"visible\"!=q.x||W&&\"visible\"!=q.x)r",
-    "eturn Y;e=ec(a);return e==Y?Y:\"scroll\"}L=e.left>=A.left+A.width;A=e.t",
-    "op>=A.top+A.height;if(L&&\"hidden\"==q.x||A&&\"hidden\"==q.y)return Y;i",
-    "f(L&&\"visible\"!=q.x||A&&\"visible\"!=q.y){if(D&&(q=d(a),e.left>=g.scr",
-    "ollWidth-q.x||e.right>=g.scrollHeight-q.y))return Y;e=ec(a);return e==Y",
-    "?Y:\"scroll\"}}}return\"none\"}\nfunction dc(a){var b=fc(a);if(b)return",
-    " b.rect;if(C(a,\"HTML\"))return a=z(a),a=((a?a.parentWindow||a.defaultV",
-    "iew:window)||window).document,a=\"CSS1Compat\"==a.compatMode?a.document",
-    "Element:a.body,a=new Fa(a.clientWidth,a.clientHeight),new V(0,0,a.width",
-    ",a.height);try{var c=a.getBoundingClientRect()}catch(d){return new V(0,",
-    "0,0,0)}return new V(c.left,c.top,c.right-c.left,c.bottom-c.top)}\nfunct",
-    "ion fc(a){var b=C(a,\"MAP\");if(!b&&!C(a,\"AREA\"))return null;var c=b?",
-    "a:C(a.parentNode,\"MAP\")?a.parentNode:null,d=null,e=null;c&&c.name&&(d",
-    "=U.u('/descendant::*[@usemap = \"#'+c.name+'\"]',z(c)))&&(e=dc(d),b||\"",
-    "default\"==a.shape.toLowerCase()||(a=jc(a),b=Math.min(Math.max(a.left,0",
-    "),e.width),c=Math.min(Math.max(a.top,0),e.height),e=new V(b+e.left,c+e.",
-    "top,Math.min(a.width,e.width-b),Math.min(a.height,e.height-c))));return",
-    "{ba:d,rect:e||new V(0,0,0,0)}}\nfunction jc(a){var b=a.shape.toLowerCas",
-    "e();a=a.coords.split(\",\");if(\"rect\"==b&&4==a.length){var b=a[0],c=a",
-    "[1];return new V(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.length)retur",
-    "n b=a[2],new V(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.length){for(v",
-    "ar b=a[0],c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Mat",
-    "h.max(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new V(b,",
-    "c,d-b,e-c)}return new V(0,0,0,0)}function ic(a){a=dc(a);return new Zb(a",
-    ".top,a.left+a.width,a.top+a.height,a.left)}\nfunction kc(a){return a.re",
-    "place(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g,\"\")}function lc(a){var b=[];$b?m",
-    "c(a,b):nc(a,b);var c=b;a=c.length;for(var b=Array(a),c=m(c)?c.split(\"",
-    "\"):c,d=0;d<a;d++)d in c&&(b[d]=kc.call(void 0,c[d]));return kc(b.join(",
-    "\"\\n\")).replace(/\\xa0/g,\" \")}\nfunction oc(a,b,c){if(C(a,\"BR\"))b",
-    ".push(\"\");else{var d=C(a,\"TD\"),e=X(a,\"display\"),f=!d&&!(0<=oa(pc,",
-    "e)),g=l(a.previousElementSibling)?a.previousElementSibling:Ja(a.previou",
-    "sSibling),g=g?X(g,\"display\"):\"\",k=X(a,\"float\")||X(a,\"cssFloat\")",
-    "||X(a,\"styleFloat\");!f||\"run-in\"==g&&\"none\"==k||/^[\\s\\xa0]*$/.t",
-    "est(b[b.length-1]||\"\")||b.push(\"\");var u=hc(a),D=null,q=null;u&&(D=",
-    "X(a,\"white-space\"),q=X(a,\"text-transform\"));t(a.childNodes,function",
-    "(a){c(a,b,u,D,q)});a=b[b.length-1]||\"\";!d&&\"table-cell\"!=e||!a||la(",
-    "a)||(b[b.length-\n1]+=\" \");f&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)",
-    "&&b.push(\"\")}}function nc(a,b){oc(a,b,function(a,b,e,f,g){3==a.nodeTy",
-    "pe&&e?qc(a,b,f,g):C(a)&&nc(a,b)})}var pc=\"inline inline-block inline-t",
-    "able none table-cell table-column table-column-group\".split(\" \");\nf",
-    "unction qc(a,b,c,d){a=a.nodeValue.replace(/[\\u200b\\u200e\\u200f]/g,\"",
-    "\");a=a.replace(/(\\r\\n|\\r|\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap",
-    "\"==c)a=a.replace(/\\n/g,\" \");a=\"pre\"==c||\"pre-wrap\"==c?a.replace",
-    "(/[ \\f\\t\\v\\u2028\\u2029]/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u",
-    "2028\\u2029]+/g,\" \");\"capitalize\"==d?a=a.replace(/(^|\\s)(\\S)/g,fu",
-    "nction(a,b,c){return b+c.toUpperCase()}):\"uppercase\"==d?a=a.toUpperCa",
-    "se():\"lowercase\"==d&&(a=a.toLowerCase());c=b.pop()||\"\";la(c)&&0==a.",
-    "lastIndexOf(\" \",0)&&(a=a.substr(1));b.push(c+a)}\nfunction gc(a){var ",
-    "b=1,c=X(a,\"opacity\");c&&(b=Number(c));(a=ac(a))&&(b*=gc(a));return b}",
-    "\nfunction rc(a,b,c,d,e){var f;if(3==a.nodeType&&c)qc(a,b,d,e);else if(",
-    "C(a))if(C(a,\"CONTENT\")){for(f=a;f.parentNode;)f=f.parentNode;f instan",
-    "ceof ShadowRoot?t(a.getDistributedNodes(),function(a){rc(a,b,c,d,e)}):m",
-    "c(a,b)}else if(C(a,\"SHADOW\")){for(f=a;f.parentNode;)f=f.parentNode;if",
-    "(f instanceof ShadowRoot&&(a=f))for(a=a.olderShadowRoot;a;)t(a.childNod",
-    "es,function(a){rc(a,b,c,d,e)}),a=a.olderShadowRoot}else mc(a,b)}\nfunct",
-    "ion mc(a,b){a.shadowRoot&&t(a.shadowRoot.childNodes,function(a){rc(a,b,",
-    "!0,null,null)});oc(a,b,function(a,b,e,f,g){var c=null;1==a.nodeType?c=a",
-    ":3==a.nodeType&&(c=a);null!=c&&c.getDestinationInsertionPoints&&0<c.get",
-    "DestinationInsertionPoints().length||rc(a,b,e,f,g)})};var sc={K:functio",
-    "n(a){return!(!a.querySelectorAll||!a.querySelector)},u:function(a,b){if",
-    "(!a)throw new v(32,\"No class name specified\");a=ma(a);if(-1!==a.index",
-    "Of(\" \"))throw new v(32,\"Compound class names not permitted\");if(sc.",
-    "K(b))try{return b.querySelector(\".\"+a.replace(/\\./g,\"\\\\.\"))||nul",
-    "l}catch(c){throw new v(32,\"An invalid or illegal class name was specif",
-    "ied\");}a=B(y(b),\"*\",a,b);return a.length?a[0]:null},l:function(a,b){",
-    "if(!a)throw new v(32,\"No class name specified\");a=ma(a);if(-1!==a.ind",
-    "exOf(\" \"))throw new v(32,\n\"Compound class names not permitted\");if",
-    "(sc.K(b))try{return b.querySelectorAll(\".\"+a.replace(/\\./g,\"\\\\.\"",
-    "))}catch(c){throw new v(32,\"An invalid or illegal class name was speci",
-    "fied\");}return B(y(b),\"*\",a,b)}};var tc={u:function(a,b){p(b.querySe",
-    "lector);if(!a)throw new v(32,\"No selector specified\");a=ma(a);try{var",
-    " c=b.querySelector(a)}catch(d){throw new v(32,\"An invalid or illegal s",
-    "elector was specified\");}return c&&1==c.nodeType?c:null},l:function(a,",
-    "b){p(b.querySelectorAll);if(!a)throw new v(32,\"No selector specified\"",
-    ");a=ma(a);try{return b.querySelectorAll(a)}catch(c){throw new v(32,\"An",
-    " invalid or illegal selector was specified\");}}};var uc={K:function(a,",
-    "b){return!(!a.querySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)},u",
-    ":function(a,b){var c=y(b),d=m(a)?c.C.getElementById(a):a;return d?Pa(d,",
-    "\"id\")==a&&Ka(b,d)?d:ta(B(c,\"*\"),function(c){return Pa(c,\"id\")==a&",
-    "&Ka(b,c)}):null},l:function(a,b){if(!a)return[];if(uc.K(b,a))try{return",
-    " b.querySelectorAll(\"#\"+uc.na(a))}catch(c){return[]}b=B(y(b),\"*\",nu",
-    "ll,b);return pa(b,function(b){return Pa(b,\"id\")==a})},na:function(a){",
-    "return a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[\\]\\(\\)]",
-    ")/g,\"\\\\$1\")}};var Z={},vc={};Z.ja=function(a,b,c){try{var d=tc.l(\"",
-    "a\",b)}catch(e){d=B(y(b),\"A\",null,b)}return ta(d,function(b){b=lc(b);",
-    "return c&&-1!=b.indexOf(a)||b==a})};Z.ea=function(a,b,c){try{var d=tc.l",
-    "(\"a\",b)}catch(e){d=B(y(b),\"A\",null,b)}return pa(d,function(b){b=lc(",
-    "b);return c&&-1!=b.indexOf(a)||b==a})};Z.u=function(a,b){return Z.ja(a,",
-    "b,!1)};Z.l=function(a,b){return Z.ea(a,b,!1)};vc.u=function(a,b){return",
-    " Z.ja(a,b,!0)};vc.l=function(a,b){return Z.ea(a,b,!0)};var wc={u:functi",
-    "on(a,b){if(\"\"===a)throw new v(32,'Unable to locate an element with th",
-    "e tagName \"\"');return b.getElementsByTagName(a)[0]||null},l:function(",
-    "a,b){if(\"\"===a)throw new v(32,'Unable to locate an element with the t",
-    "agName \"\"');return b.getElementsByTagName(a)}};var xc={className:sc,",
-    "\"class name\":sc,css:tc,\"css selector\":tc,id:uc,linkText:Z,\"link te",
-    "xt\":Z,name:{u:function(a,b){b=B(y(b),\"*\",null,b);return ta(b,functio",
-    "n(b){return Pa(b,\"name\")==a})},l:function(a,b){b=B(y(b),\"*\",null,b)",
-    ";return pa(b,function(b){return Pa(b,\"name\")==a})}},partialLinkText:v",
-    "c,\"partial link text\":vc,tagName:wc,\"tag name\":wc,xpath:U};function",
-    " yc(a){for(var b in a)if(a.hasOwnProperty(b))return b;return null};var ",
-    "zc=\"function\"===typeof ShadowRoot;ba(\"_\",function(a,b){var c;a:{if(",
-    "c=yc(a)){var d=xc[c];if(d&&p(d.u)){c=d.u(a[c],b||ja.document);break a}}",
-    "throw Error(\"Unsupported locator strategy: \"+c);}if(c)return c;if(zc&",
-    "&b){for(c=b;c.parentNode;)c=c.parentNode;if(c instanceof ShadowRoot){a:",
-    "{if((c=yc(a))&&(d=xc[c])&&p(d.l)){a=d.l(a[c],b||ja.document);break a}th",
-    "row Error(\"Unsupported locator strategy: \"+c);}if(c=a[0])return c}}re",
-    "turn null});; return this._.apply(null,arguments);}.apply({navigator:ty",
-    "peof window!='undefined'?window.navigator:null,document:typeof window!=",
-    "'undefined'?window.document:null}, arguments);}",
+    "=gc(a))&&d(a)?!e(a):!1}\nfunction hc(a){function b(a){if(C(a)&&\"none\"",
+    "==X(a,\"display\"))return!1;var c;(c=a.parentNode)&&c.shadowRoot&&void ",
+    "0!==a.assignedSlot?c=a.assignedSlot?a.assignedSlot.parentNode:null:a.ge",
+    "tDestinationInsertionPoints&&(a=a.getDestinationInsertionPoints(),0<a.l",
+    "ength&&(c=a[a.length-1]));return $b&&c instanceof ShadowRoot||c&&(9==c.",
+    "nodeType||11==c.nodeType)?!0:!!c&&b(c)}return cc(a,!1,b)}var Y=\"hidden",
+    "\";\nfunction ec(a){function b(a){function b(a){return a==g?!0:0==X(a,",
+    "\"display\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"static\"==X(",
+    "a,\"position\")?!1:!0}var c=X(a,\"position\");if(\"fixed\"==c)return D=",
+    "!0,a==g?null:g;for(a=ac(a);a&&!b(a);)a=ac(a);return a}function c(a){var",
+    " b=a;if(\"visible\"==u)if(a==g&&k)b=k;else if(a==k)return{x:\"visible\"",
+    ",y:\"visible\"};b={x:X(b,\"overflow-x\"),y:X(b,\"overflow-y\")};a==g&&(",
+    "b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);re",
+    "turn b}function d(a){if(a==g){var b=(new Ga(f)).C;\na=b.scrollingElemen",
+    "t?b.scrollingElement:b.body||b.documentElement;b=b.parentWindow||b.defa",
+    "ultView;a=new x(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scrollTop)",
+    "}else a=new x(a.scrollLeft,a.scrollTop);return a}var e=ic(a);var f=z(a)",
+    ",g=f.documentElement,k=f.body,u=X(g,\"overflow\"),D;for(a=b(a);a;a=b(a)",
+    "){var r=c(a);if(\"visible\"!=r.x||\"visible\"!=r.y){var A=dc(a);if(0==A",
+    ".width||0==A.height)return Y;var L=e.right<A.left,W=e.bottom<A.top;if(L",
+    "&&\"hidden\"==r.x||W&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!=r.x||",
+    "\nW&&\"visible\"!=r.y){L=d(a);W=e.bottom<A.top-L.y;if(e.right<A.left-L.",
+    "x&&\"visible\"!=r.x||W&&\"visible\"!=r.x)return Y;e=ec(a);return e==Y?Y",
+    ":\"scroll\"}L=e.left>=A.left+A.width;A=e.top>=A.top+A.height;if(L&&\"hi",
+    "dden\"==r.x||A&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!=r.x||A&&\"v",
+    "isible\"!=r.y){if(D&&(r=d(a),e.left>=g.scrollWidth-r.x||e.right>=g.scro",
+    "llHeight-r.y))return Y;e=ec(a);return e==Y?Y:\"scroll\"}}}return\"none",
+    "\"}\nfunction dc(a){var b=fc(a);if(b)return b.rect;if(C(a,\"HTML\"))ret",
+    "urn a=z(a),a=((a?a.parentWindow||a.defaultView:window)||window).documen",
+    "t,a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=new Fa(a.cl",
+    "ientWidth,a.clientHeight),new V(0,0,a.width,a.height);try{var c=a.getBo",
+    "undingClientRect()}catch(d){return new V(0,0,0,0)}return new V(c.left,c",
+    ".top,c.right-c.left,c.bottom-c.top)}\nfunction fc(a){var b=C(a,\"MAP\")",
+    ";if(!b&&!C(a,\"AREA\"))return null;var c=b?a:C(a.parentNode,\"MAP\")?a.",
+    "parentNode:null,d=null,e=null;c&&c.name&&(d=U.u('/descendant::*[@usemap",
+    " = \"#'+c.name+'\"]',z(c)))&&(e=dc(d),b||\"default\"==a.shape.toLowerCa",
+    "se()||(a=jc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.min(Math.m",
+    "ax(a.top,0),e.height),e=new V(b+e.left,c+e.top,Math.min(a.width,e.width",
+    "-b),Math.min(a.height,e.height-c))));return{ba:d,rect:e||new V(0,0,0,0)",
+    "}}\nfunction jc(a){var b=a.shape.toLowerCase();a=a.coords.split(\",\");",
+    "if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new V(b,c,a[2]-b,",
+    "a[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new V(a[0]-b,a[1]-b",
+    ",2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2",
+    ";f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a",
+    "[f+1]),e=Math.max(e,a[f+1]);return new V(b,c,d-b,e-c)}return new V(0,0,",
+    "0,0)}function ic(a){a=dc(a);return new Zb(a.top,a.left+a.width,a.top+a.",
+    "height,a.left)}\nfunction kc(a){return a.replace(/^[^\\S\\xa0]+|[^\\S",
+    "\\xa0]+$/g,\"\")}function lc(a){var b=[];$b?mc(a,b):nc(a,b);var c=b;a=c",
+    ".length;for(var b=Array(a),c=m(c)?c.split(\"\"):c,d=0;d<a;d++)d in c&&(",
+    "b[d]=kc.call(void 0,c[d]));return kc(b.join(\"\\n\")).replace(/\\xa0/g,",
+    "\" \")}\nfunction oc(a,b,c){if(C(a,\"BR\"))b.push(\"\");else{var d=C(a,",
+    "\"TD\"),e=X(a,\"display\"),f=!d&&!(0<=oa(pc,e)),g=l(a.previousElementSi",
+    "bling)?a.previousElementSibling:Ja(a.previousSibling),g=g?X(g,\"display",
+    "\"):\"\",k=X(a,\"float\")||X(a,\"cssFloat\")||X(a,\"styleFloat\");!f||",
+    "\"run-in\"==g&&\"none\"==k||/^[\\s\\xa0]*$/.test(b[b.length-1]||\"\")||",
+    "b.push(\"\");var u=hc(a),D=null,r=null;u&&(D=X(a,\"white-space\"),r=X(a",
+    ",\"text-transform\"));t(a.childNodes,function(a){c(a,b,u,D,r)});a=b[b.l",
+    "ength-1]||\"\";!d&&\"table-cell\"!=e||!a||la(a)||(b[b.length-\n1]+=\" ",
+    "\");f&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(\"\")}}function ",
+    "nc(a,b){oc(a,b,function(a,b,e,f,g){3==a.nodeType&&e?qc(a,b,f,g):C(a)&&n",
+    "c(a,b)})}var pc=\"inline inline-block inline-table none table-cell tabl",
+    "e-column table-column-group\".split(\" \");\nfunction qc(a,b,c,d){a=a.n",
+    "odeValue.replace(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.replace(/(\\r\\n|",
+    "\\r|\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.replace(/\\n/g,",
+    "\" \");a=\"pre\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u2028\\u20",
+    "29]/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u2029]+/g,\" \");\"",
+    "capitalize\"==d?a=a.replace(/(^|\\s)(\\S)/g,function(a,b,c){return b+c.",
+    "toUpperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"==d&&(a",
+    "=a.toLowerCase());c=b.pop()||\"\";la(c)&&0==a.lastIndexOf(\" \",0)&&(a=",
+    "a.substr(1));b.push(c+a)}\nfunction gc(a){var b=1,c=X(a,\"opacity\");c&",
+    "&(b=Number(c));(a=ac(a))&&(b*=gc(a));return b}\nfunction rc(a,b,c,d,e){",
+    "var f;if(3==a.nodeType&&c)qc(a,b,d,e);else if(C(a))if(C(a,\"CONTENT\")|",
+    "|C(a,\"SLOT\")){for(f=a;f.parentNode;)f=f.parentNode;f instanceof Shado",
+    "wRoot?(a=C(a,\"CONTENT\")?a.getDistributedNodes():a.assignedNodes(),t(a",
+    ",function(a){rc(a,b,c,d,e)})):mc(a,b)}else if(C(a,\"SHADOW\")){for(f=a;",
+    "f.parentNode;)f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.",
+    "olderShadowRoot;a;)t(a.childNodes,function(a){rc(a,b,c,d,e)}),a=a.older",
+    "ShadowRoot}else mc(a,b)}\nfunction mc(a,b){a.shadowRoot&&t(a.shadowRoot",
+    ".childNodes,function(a){rc(a,b,!0,null,null)});oc(a,b,function(a,b,e,f,",
+    "g){var c=null;1==a.nodeType?c=a:3==a.nodeType&&(c=a);null!=c&&(null!=c.",
+    "assignedSlot||c.getDestinationInsertionPoints&&0<c.getDestinationInsert",
+    "ionPoints().length)||rc(a,b,e,f,g)})};var sc={K:function(a){return!(!a.",
+    "querySelectorAll||!a.querySelector)},u:function(a,b){if(!a)throw new v(",
+    "32,\"No class name specified\");a=ma(a);if(-1!==a.indexOf(\" \"))throw ",
+    "new v(32,\"Compound class names not permitted\");if(sc.K(b))try{return ",
+    "b.querySelector(\".\"+a.replace(/\\./g,\"\\\\.\"))||null}catch(c){throw",
+    " new v(32,\"An invalid or illegal class name was specified\");}a=B(y(b)",
+    ",\"*\",a,b);return a.length?a[0]:null},l:function(a,b){if(!a)throw new ",
+    "v(32,\"No class name specified\");a=ma(a);if(-1!==a.indexOf(\" \"))thro",
+    "w new v(32,\n\"Compound class names not permitted\");if(sc.K(b))try{ret",
+    "urn b.querySelectorAll(\".\"+a.replace(/\\./g,\"\\\\.\"))}catch(c){thro",
+    "w new v(32,\"An invalid or illegal class name was specified\");}return ",
+    "B(y(b),\"*\",a,b)}};var tc={u:function(a,b){p(b.querySelector);if(!a)th",
+    "row new v(32,\"No selector specified\");a=ma(a);try{var c=b.querySelect",
+    "or(a)}catch(d){throw new v(32,\"An invalid or illegal selector was spec",
+    "ified\");}return c&&1==c.nodeType?c:null},l:function(a,b){p(b.querySele",
+    "ctorAll);if(!a)throw new v(32,\"No selector specified\");a=ma(a);try{re",
+    "turn b.querySelectorAll(a)}catch(c){throw new v(32,\"An invalid or ille",
+    "gal selector was specified\");}}};var uc={K:function(a,b){return!(!a.qu",
+    "erySelectorAll||!a.querySelector)&&!/^\\d.*/.test(b)},u:function(a,b){v",
+    "ar c=y(b),d=m(a)?c.C.getElementById(a):a;return d?Pa(d,\"id\")==a&&b!=d",
+    "&&Ka(b,d)?d:ta(B(c,\"*\"),function(c){return Pa(c,\"id\")==a&&b!=c&&Ka(",
+    "b,c)}):null},l:function(a,b){if(!a)return[];if(uc.K(b,a))try{return b.q",
+    "uerySelectorAll(\"#\"+uc.na(a))}catch(c){return[]}b=B(y(b),\"*\",null,b",
+    ");return pa(b,function(b){return Pa(b,\"id\")==a})},na:function(a){retu",
+    "rn a.replace(/([\\s'\"\\\\#.:;,!?+<>=~*^$|%&@`{}\\-\\/\\[\\]\\(\\)])/g,",
+    "\n\"\\\\$1\")}};var Z={},vc={};Z.ja=function(a,b,c){try{var d=tc.l(\"a",
+    "\",b)}catch(e){d=B(y(b),\"A\",null,b)}return ta(d,function(b){b=lc(b);b",
+    "=b.replace(/^[\\s]+|[\\s]+$/g,\"\");return c&&-1!=b.indexOf(a)||b==a})}",
+    ";Z.ea=function(a,b,c){try{var d=tc.l(\"a\",b)}catch(e){d=B(y(b),\"A\",n",
+    "ull,b)}return pa(d,function(b){b=lc(b);b=b.replace(/^[\\s]+|[\\s]+$/g,",
+    "\"\");return c&&-1!=b.indexOf(a)||b==a})};Z.u=function(a,b){return Z.ja",
+    "(a,b,!1)};Z.l=function(a,b){return Z.ea(a,b,!1)};vc.u=function(a,b){ret",
+    "urn Z.ja(a,b,!0)};\nvc.l=function(a,b){return Z.ea(a,b,!0)};var wc={u:f",
+    "unction(a,b){if(\"\"===a)throw new v(32,'Unable to locate an element wi",
+    "th the tagName \"\"');return b.getElementsByTagName(a)[0]||null},l:func",
+    "tion(a,b){if(\"\"===a)throw new v(32,'Unable to locate an element with ",
+    "the tagName \"\"');return b.getElementsByTagName(a)}};var xc={className",
+    ":sc,\"class name\":sc,css:tc,\"css selector\":tc,id:uc,linkText:Z,\"lin",
+    "k text\":Z,name:{u:function(a,b){b=B(y(b),\"*\",null,b);return ta(b,fun",
+    "ction(b){return Pa(b,\"name\")==a})},l:function(a,b){b=B(y(b),\"*\",nul",
+    "l,b);return pa(b,function(b){return Pa(b,\"name\")==a})}},partialLinkTe",
+    "xt:vc,\"partial link text\":vc,tagName:wc,\"tag name\":wc,xpath:U};func",
+    "tion yc(a){for(var b in a)if(a.hasOwnProperty(b))return b;return null};",
+    "var zc=\"function\"===typeof ShadowRoot;ba(\"_\",function(a,b){var c;a:",
+    "{if(c=yc(a)){var d=xc[c];if(d&&p(d.u)){c=d.u(a[c],b||ja.document);break",
+    " a}}throw Error(\"Unsupported locator strategy: \"+c);}if(c)return c;if",
+    "(zc&&b){for(c=b;c.parentNode;)c=c.parentNode;if(c instanceof ShadowRoot",
+    "){a:{if((c=yc(a))&&(d=xc[c])&&p(d.l)){a=d.l(a[c],b||ja.document);break ",
+    "a}throw Error(\"Unsupported locator strategy: \"+c);}if(c=a[0])return c",
+    "}}return null});; return this._.apply(null,arguments);}.apply({navigato",
+    "r:typeof window!='undefined'?window.navigator:null,document:typeof wind",
+    "ow!='undefined'?window.document:null}, arguments);}",
     NULL
 };
 
@@ -7112,7 +7121,7 @@
     "a=\"backgroundColor borderTopColor borderRightColor borderBottomColor b",
     "orderLeftColor color outlineColor\".split(\" \"),sa=/#([0-9a-fA-F])([0-",
     "9a-fA-F])([0-9a-fA-F])/,ta=/^#(?:[0-9a-f]{3}){1,2}$/i,ua=/^(?:rgba)?\\(",
-    "(\\d{1,3}),\\s?(\\d{1,3}),\\s?(\\d{1,3}),\\s?(0|1|0\\.\\d*)\\)$/i,va=/^",
+    "(\\d{1,3}),\\s?(\\d{1,3}),\\s?(\\d{1,3}),\\s?(0|1|0\\.\\d*)\\)$/i,wa=/^",
     "(?:rgb)?\\((0|[1-9]\\d{0,2}),\\s?(0|[1-9]\\d{0,2}),\\s?(0|[1-9]\\d{0,2}",
     ")\\)$/i;function xa(a,b){this.code=a;this.state=u[a]||ya;this.message=b",
     "||\"\";a=this.state.replace(/((?:^|\\s+)[a-z])/g,function(a){return a.t",
@@ -7157,12 +7166,12 @@
     "arentNode){var c=1==a.nodeType,d=1==b.nodeType;if(c&&d)return a.sourceI",
     "ndex-b.sourceIndex;var e=a.parentNode,f=b.parentNode;return e==f?Ea(a,b",
     "):!c&&Ca(e,b)?-1*Fa(a,b):!d&&Ca(f,a)?Fa(b,a):(c?a.sourceIndex:e.sourceI",
-    "ndex)-(d?b.sourceIndex:f.sourceIndex)}d=y(a);c=d.createRange();c.select",
+    "ndex)-(d?b.sourceIndex:f.sourceIndex)}d=x(a);c=d.createRange();c.select",
     "Node(a);c.collapse(!0);a=d.createRange();a.selectNode(b);\na.collapse(!",
     "0);return c.compareBoundaryPoints(aa.Range.START_TO_END,a)}function Fa(",
     "a,b){var c=a.parentNode;if(c==b)return-1;for(;b.parentNode!=c;)b=b.pare",
     "ntNode;return Ea(b,a)}function Ea(a,b){for(;b=b.previousSibling;)if(b==",
-    "a)return-1;return 1}function y(a){return 9==a.nodeType?a:a.ownerDocumen",
+    "a)return-1;return 1}function x(a){return 9==a.nodeType?a:a.ownerDocumen",
     "t||a.document}function Ba(a){if(a&&\"number\"==typeof a.length){if(ea(a",
     "))return\"function\"==typeof a.item||\"string\"==typeof a.item;if(\"fun",
     "ction\"==ca(a))return\"function\"==typeof a.item}return!1}\nfunction Ga",
@@ -7172,7 +7181,7 @@
     "mentsByTagName(String(a))};h.createElement=function(a){return this.H.cr",
     "eateElement(String(a))};h.createTextNode=function(a){return this.H.crea",
     "teTextNode(String(a))};h.appendChild=function(a,b){a.appendChild(b)};h.",
-    "append=function(a,b){Aa(y(a),a,arguments)};\nh.canHaveChildren=function",
+    "append=function(a,b){Aa(x(a),a,arguments)};\nh.canHaveChildren=function",
     "(a){if(1!=a.nodeType)return!1;switch(a.tagName){case \"APPLET\":case \"",
     "AREA\":case \"BASE\":case \"BR\":case \"COL\":case \"COMMAND\":case \"E",
     "MBED\":case \"FRAME\":case \"HR\":case \"IMG\":case \"INPUT\":case \"IF",
@@ -7238,16 +7247,16 @@
     ".w:a.next;return b.node};\nTa.prototype.remove=function(){var a=this.ka",
     ",b=this.P;if(!b)throw Error(\"Next must be called at least once before ",
     "remove.\");var c=b.w,b=b.next;c?c.next=b:a.g=b;b?b.w=c:a.j=c;a.D--;this",
-    ".P=null};function H(a){this.f=a;this.h=this.s=!1;this.F=null}function J",
-    "(a){return\"\\n  \"+a.toString().split(\"\\n\").join(\"\\n  \")}H.proto",
+    ".P=null};function I(a){this.f=a;this.h=this.s=!1;this.F=null}function J",
+    "(a){return\"\\n  \"+a.toString().split(\"\\n\").join(\"\\n  \")}I.proto",
     "type.c=function(){return this.s};function Ua(a,b){a.s=b}function Va(a,b",
-    "){a.h=b}H.prototype.v=function(){return this.F};function K(a,b){a=a.eva",
+    "){a.h=b}I.prototype.v=function(){return this.F};function K(a,b){a=a.eva",
     "luate(b);return a instanceof F?+Sa(a):+a}function L(a,b){a=a.evaluate(b",
     ");return a instanceof F?Sa(a):\"\"+a}function M(a,b){a=a.evaluate(b);re",
-    "turn a instanceof F?!!a.o():!!a};function Wa(a,b,c){H.call(this,a.f);th",
+    "turn a instanceof F?!!a.o():!!a};function Wa(a,b,c){I.call(this,a.f);th",
     "is.S=a;this.$=b;this.ea=c;this.s=b.c()||c.c();this.h=b.h||c.h;this.S==X",
     "a&&(c.h||c.c()||4==c.f||0==c.f||!b.v()?b.h||b.c()||4==b.f||0==b.f||!c.v",
-    "()||(this.F={name:c.v().name,C:b}):this.F={name:b.v().name,C:c})}p(Wa,H",
+    "()||(this.F={name:c.v().name,C:b}):this.F={name:b.v().name,C:c})}p(Wa,I",
     ");\nfunction N(a,b,c,d,e){b=b.evaluate(d);c=c.evaluate(d);var f;if(b in",
     "stanceof F&&c instanceof F){b=b.iterator();for(d=b.next();d;d=b.next())",
     "for(e=c.iterator(),f=e.next();f;f=e.next())if(a(C(d),C(f)))return!0;ret",
@@ -7277,18 +7286,18 @@
     ")});O(\"and\",2,2,function(a,b,c){return M(a,c)&&M(b,c)});O(\"or\",1,2,",
     "function(a,b,c){return M(a,c)||M(b,c)});function $a(a,b){if(b.o()&&4!=a",
     ".f)throw Error(\"Primary expression must evaluate to nodeset if filter ",
-    "has predicate(s).\");H.call(this,a.f);this.da=a;this.b=b;this.s=a.c();t",
-    "his.h=a.h}p($a,H);$a.prototype.evaluate=function(a){a=this.da.evaluate(",
+    "has predicate(s).\");I.call(this,a.f);this.da=a;this.b=b;this.s=a.c();t",
+    "his.h=a.h}p($a,I);$a.prototype.evaluate=function(a){a=this.da.evaluate(",
     "a);return ab(this.b,a)};$a.prototype.toString=function(){var a=\"Filter",
     ":\"+J(this.da);return a+=J(this.b)};function bb(a,b){if(b.length<a.ba)t",
     "hrow Error(\"Function \"+a.i+\" expects at least\"+a.ba+\" arguments, ",
     "\"+b.length+\" given\");if(null!==a.R&&b.length>a.R)throw Error(\"Funct",
     "ion \"+a.i+\" expects at most \"+a.R+\" arguments, \"+b.length+\" given",
     "\");a.la&&r(b,function(b,d){if(4!=b.f)throw Error(\"Argument \"+d+\" to",
-    " function \"+a.i+\" is not of type Nodeset: \"+b);});H.call(this,a.f);t",
+    " function \"+a.i+\" is not of type Nodeset: \"+b);});I.call(this,a.f);t",
     "his.I=a;this.N=b;Ua(this,a.s||la(b,function(a){return a.c()}));Va(this,",
     "a.ja&&!b.length||a.ia&&!!b.length||la(b,function(a){return a.h}))}\np(b",
-    "b,H);bb.prototype.evaluate=function(a){return this.I.m.apply(null,na(a,",
+    "b,I);bb.prototype.evaluate=function(a){return this.I.m.apply(null,na(a,",
     "this.N))};bb.prototype.toString=function(){var a=\"Function: \"+this.I;",
     "if(this.N.length)var b=t(this.N,function(a,b){return a+J(b)},\"Argument",
     "s:\"),a=a+J(b);return a};function cb(a,b,c,d,e,f,g,l,w){this.i=a;this.f",
@@ -7341,8 +7350,8 @@
     "uction\"==a||\"node\"==a}G.prototype.matches=function(a){return null===",
     "this.B||this.B==a.nodeType};G.prototype.getName=function(){return this.",
     "ga};\nG.prototype.toString=function(){var a=\"Kind Test: \"+this.ga;nul",
-    "l===this.aa||(a+=J(this.aa));return a};function fb(a){H.call(this,3);th",
-    "is.fa=a.substring(1,a.length-1)}p(fb,H);fb.prototype.evaluate=function(",
+    "l===this.aa||(a+=J(this.aa));return a};function fb(a){I.call(this,3);th",
+    "is.fa=a.substring(1,a.length-1)}p(fb,I);fb.prototype.evaluate=function(",
     "){return this.fa};fb.prototype.toString=function(){return\"Literal: \"+",
     "this.fa};function gb(a,b){this.i=a.toLowerCase();a=\"*\"==this.i?\"*\":",
     "\"http://www.w3.org/1999/xhtml\";this.K=b?b.toLowerCase():a}gb.prototyp",
@@ -7352,15 +7361,15 @@
     "Case():\"http://www.w3.org/1999/xhtml\")};gb.prototype.getName=function",
     "(){return this.i};\ngb.prototype.toString=function(){return\"Name Test:",
     " \"+(\"http://www.w3.org/1999/xhtml\"==this.K?\"\":this.K+\":\")+this.i",
-    "};function hb(a){H.call(this,1);this.ha=a}p(hb,H);hb.prototype.evaluate",
+    "};function hb(a){I.call(this,1);this.ha=a}p(hb,I);hb.prototype.evaluate",
     "=function(){return this.ha};hb.prototype.toString=function(){return\"Nu",
-    "mber: \"+this.ha};function ib(a,b){H.call(this,a.f);this.Y=a;this.G=b;t",
+    "mber: \"+this.ha};function ib(a,b){I.call(this,a.f);this.Y=a;this.G=b;t",
     "his.s=a.c();this.h=a.h;1==this.G.length&&(a=this.G[0],a.O||a.u!=jb||(a=",
-    "a.M,\"*\"!=a.getName()&&(this.F={name:a.getName(),C:null})))}p(ib,H);fu",
-    "nction kb(){H.call(this,4)}p(kb,H);kb.prototype.evaluate=function(a){va",
+    "a.M,\"*\"!=a.getName()&&(this.F={name:a.getName(),C:null})))}p(ib,I);fu",
+    "nction kb(){I.call(this,4)}p(kb,I);kb.prototype.evaluate=function(a){va",
     "r b=new F;a=a.l;9==a.nodeType?b.add(a):b.add(a.ownerDocument);return b}",
     ";kb.prototype.toString=function(){return\"Root Helper Expression\"};fun",
-    "ction lb(){H.call(this,4)}p(lb,H);lb.prototype.evaluate=function(a){var",
+    "ction lb(){I.call(this,4)}p(lb,I);lb.prototype.evaluate=function(a){var",
     " b=new F;b.add(a.l);return b};\nlb.prototype.toString=function(){return",
     "\"Context Helper Expression\"};function mb(a){return\"/\"==a||\"//\"==a",
     "}\nib.prototype.evaluate=function(a){var b=this.Y.evaluate(a);if(!(b in",
@@ -7383,9 +7392,9 @@
     "his.b.length;a++){var b=this.b[a];if(b.c()||1==b.f||0==b.f)return!0}ret",
     "urn!1};Q.prototype.o=function(){return this.b.length};Q.prototype.toStr",
     "ing=function(){return t(this.b,function(a,b){return a+J(b)},\"Predicate",
-    "s:\")};function R(a,b,c,d){H.call(this,4);this.u=a;this.M=b;this.b=c||n",
+    "s:\")};function R(a,b,c,d){I.call(this,4);this.u=a;this.M=b;this.b=c||n",
     "ew Q([]);this.O=!!d;b=this.b.v();a.qa&&b&&(this.F={name:b.name,C:b.C});",
-    "this.s=this.b.c()}p(R,H);\nR.prototype.evaluate=function(a){var b=a.l,c",
+    "this.s=this.b.c()}p(R,I);\nR.prototype.evaluate=function(a){var b=a.l,c",
     "=this.v(),d=null,e=null,f=0;c&&(d=c.name,e=c.C?L(c.C,a):null,f=1);if(th",
     "is.O)if(this.c()||this.u!=pb)if(b=(new R(qb,new G(\"node\"))).evaluate(",
     "a).iterator(),c=b.next())for(a=this.m(c,d,e,f);null!=(c=b.next());)a=Qa",
@@ -7422,12 +7431,12 @@
     ")&&e.add(b),e=Ma(a,b,c,d,e)}return e},!0,!0);\nT(\"preceding-sibling\",",
     "function(a,b){for(var c=new F;b=b.previousSibling;)a.matches(b)&&c.unsh",
     "ift(b);return c},!0);var ub=T(\"self\",function(a,b){var c=new F;a.matc",
-    "hes(b)&&c.add(b);return c},!1);function vb(a){H.call(this,1);this.X=a;t",
-    "his.s=a.c();this.h=a.h}p(vb,H);vb.prototype.evaluate=function(a){return",
+    "hes(b)&&c.add(b);return c},!1);function vb(a){I.call(this,1);this.X=a;t",
+    "his.s=a.c();this.h=a.h}p(vb,I);vb.prototype.evaluate=function(a){return",
     "-K(this.X,a)};vb.prototype.toString=function(){return\"Unary Expression",
-    ": -\"+J(this.X)};function wb(a){H.call(this,4);this.L=a;Ua(this,la(this",
+    ": -\"+J(this.X)};function wb(a){I.call(this,4);this.L=a;Ua(this,la(this",
     ".L,function(a){return a.c()}));Va(this,la(this.L,function(a){return a.h",
-    "}))}p(wb,H);wb.prototype.evaluate=function(a){var b=new F;r(this.L,func",
+    "}))}p(wb,I);wb.prototype.evaluate=function(a){var b=new F;r(this.L,func",
     "tion(c){c=c.evaluate(a);if(!(c instanceof F))throw Error(\"Path express",
     "ion must evaluate to NodeSet.\");b=Qa(b,c)});return b};wb.prototype.toS",
     "tring=function(){return t(this.L,function(a,b){return a+J(b)},\"Union E",
@@ -7513,24 +7522,24 @@
     "n=function(a,b){return new Jb(a,b)},c.createNSResolver=function(a){retu",
     "rn new Kb(a)}});var W={};W.U=function(){var a={ua:\"http://www.w3.org/2",
     "000/svg\"};return function(b){return a[b]||null}}();\nW.m=function(a,b,",
-    "c){var d=y(a);if(!d.documentElement)return null;try{for(var e=d.createN",
+    "c){var d=x(a);if(!d.documentElement)return null;try{for(var e=d.createN",
     "SResolver?d.createNSResolver(d.documentElement):W.U,f={},g=d.getElement",
     "sByTagName(\"*\"),l=0;l<g.length;++l){var w=g[l],D=w.namespaceURI;if(D&",
-    "&!f[D]){var q=w.lookupPrefix(D);if(!q)var x=D.match(\".*/(\\\\w+)/?$\")",
-    ",q=x?x[1]:\"xhtml\";f[D]=q}}var I={},S;for(S in f)I[f[S]]=S;e=function(",
-    "a){return I[a]||null};try{return d.evaluate(b,a,e,c,null)}catch(wa){if(",
-    "\"TypeError\"===wa.name)return e=d.createNSResolver?d.createNSResolver(",
-    "d.documentElement):\nW.U,d.evaluate(b,a,e,c,null);throw wa;}}catch(wa){",
+    "&!f[D]){var q=w.lookupPrefix(D);if(!q)var y=D.match(\".*/(\\\\w+)/?$\")",
+    ",q=y?y[1]:\"xhtml\";f[D]=q}}var H={},S;for(S in f)H[f[S]]=S;e=function(",
+    "a){return H[a]||null};try{return d.evaluate(b,a,e,c,null)}catch(va){if(",
+    "\"TypeError\"===va.name)return e=d.createNSResolver?d.createNSResolver(",
+    "d.documentElement):\nW.U,d.evaluate(b,a,e,c,null);throw va;}}catch(va){",
     "throw new xa(32,\"Unable to locate an element with the xpath expression",
-    " \"+b+\" because of the following error:\\n\"+wa);}};W.V=function(a,b){",
+    " \"+b+\" because of the following error:\\n\"+va);}};W.V=function(a,b){",
     "if(!a||1!=a.nodeType)throw new xa(32,'The result of the xpath expressio",
     "n \"'+b+'\" is: '+a+\". It should be an element.\");};\nW.pa=function(a",
     ",b){var c=function(){var c=W.m(b,a,9);return c?c.singleNodeValue||null:",
-    "b.selectSingleNode?(c=y(b),c.setProperty&&c.setProperty(\"SelectionLang",
+    "b.selectSingleNode?(c=x(b),c.setProperty&&c.setProperty(\"SelectionLang",
     "uage\",\"XPath\"),b.selectSingleNode(a)):null}();null===c||W.V(c,a);ret",
     "urn c};\nW.sa=function(a,b){var c=function(){var c=W.m(b,a,7);if(c){for",
     "(var e=c.snapshotLength,f=[],g=0;g<e;++g)f.push(c.snapshotItem(g));retu",
-    "rn f}return b.selectNodes?(c=y(b),c.setProperty&&c.setProperty(\"Select",
+    "rn f}return b.selectNodes?(c=x(b),c.setProperty&&c.setProperty(\"Select",
     "ionLanguage\",\"XPath\"),b.selectNodes(a)):[]}();r(c,function(b){W.V(b,",
     "a)});return c};function Lb(a,b,c,d){this.top=a;this.right=b;this.bottom",
     "=c;this.left=d}h=Lb.prototype;h.clone=function(){return new Lb(this.top",
@@ -7573,13 +7582,13 @@
     "nction\"===typeof ShadowRoot;function Nb(a){for(a=a.parentNode;a&&1!=a.",
     "nodeType&&9!=a.nodeType&&11!=a.nodeType;)a=a.parentNode;return z(a)?a:n",
     "ull}\nfunction Y(a,b){b=ja(b);if(\"float\"==b||\"cssFloat\"==b||\"style",
-    "Float\"==b)b=\"cssFloat\";a:{var c=b;var d=y(a);if(d.defaultView&&d.def",
+    "Float\"==b)b=\"cssFloat\";a:{var c=b;var d=x(a);if(d.defaultView&&d.def",
     "aultView.getComputedStyle&&(d=d.defaultView.getComputedStyle(a,null))){",
     "c=d[c]||d.getPropertyValue(c)||\"\";break a}c=\"\"}a=c||Ob(a,b);if(null",
     "===a)a=null;else if(0<=ka(ra,b)){b:{var e=a.match(ua);if(e&&(b=Number(e",
     "[1]),c=Number(e[2]),d=Number(e[3]),e=Number(e[4]),0<=b&&255>=b&&0<=c&&2",
     "55>=c&&0<=d&&255>=d&&0<=e&&1>=e)){b=[b,c,d,e];break b}b=null}if(!b)b:{i",
-    "f(d=a.match(va))if(b=Number(d[1]),\nc=Number(d[2]),d=Number(d[3]),0<=b&",
+    "f(d=a.match(wa))if(b=Number(d[1]),\nc=Number(d[2]),d=Number(d[3]),0<=b&",
     "&255>=b&&0<=c&&255>=c&&0<=d&&255>=d){b=[b,c,d,1];break b}b=null}if(!b)b",
     ":{b=a.toLowerCase();c=qa[b.toLowerCase()];if(!c&&(c=\"#\"==b.charAt(0)?",
     "b:\"#\"+b,4==c.length&&(c=c.replace(sa,\"#$1$1$2$2$3$3\")),!ta.test(c))",
@@ -7599,59 +7608,59 @@
     "width&&0<f.rect.height&&Pb(f.Z,b,c);if(z(a,\"INPUT\")&&\"hidden\"==a.ty",
     "pe.toLowerCase()||z(a,\"NOSCRIPT\"))return!1;f=Y(a,\"visibility\");retu",
     "rn\"collapse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!=Tb(a))&&d(a)?!e(a):!1}\n",
-    "function Ub(a,b){var c=Mb?function(b){if(\"none\"==Y(b,\"display\"))ret",
-    "urn!1;do{var d=b.parentNode;if(b.getDestinationInsertionPoints){var f=b",
-    ".getDestinationInsertionPoints();0<f.length&&(d=f[f.length-1])}if(d ins",
-    "tanceof ShadowRoot)return!0;!d||9!=d.nodeType&&11!=d.nodeType||(d=null)",
-    "}while(a&&1!=a.nodeType);return!d||c(d)}:function(a){if(\"none\"==Y(a,",
-    "\"display\"))return!1;a=Nb(a);return!a||c(a)};return Pb(a,!!b,c)}var Z=",
-    "\"hidden\";\nfunction Rb(a){function b(a){function b(a){return a==g?!0:",
-    "0==Y(a,\"display\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"stati",
-    "c\"==Y(a,\"position\")?!1:!0}var c=Y(a,\"position\");if(\"fixed\"==c)re",
-    "turn D=!0,a==g?null:g;for(a=Nb(a);a&&!b(a);)a=Nb(a);return a}function c",
-    "(a){var b=a;if(\"visible\"==w)if(a==g&&l)b=l;else if(a==l)return{x:\"vi",
-    "sible\",y:\"visible\"};b={x:Y(b,\"overflow-x\"),y:Y(b,\"overflow-y\")};",
-    "a==g&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":",
-    "b.y);return b}function d(a){if(a==g){var b=(new Ha(f)).H;\na=b.scrollin",
-    "gElement?b.scrollingElement:b.body||b.documentElement;b=b.parentWindow|",
-    "|b.defaultView;a=new v(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scr",
-    "ollTop)}else a=new v(a.scrollLeft,a.scrollTop);return a}var e=Vb(a);var",
-    " f=y(a),g=f.documentElement,l=f.body,w=Y(g,\"overflow\"),D;for(a=b(a);a",
-    ";a=b(a)){var q=c(a);if(\"visible\"!=q.x||\"visible\"!=q.y){var x=Qb(a);",
-    "if(0==x.width||0==x.height)return Z;var I=e.right<x.left,S=e.bottom<x.t",
-    "op;if(I&&\"hidden\"==q.x||S&&\"hidden\"==q.y)return Z;if(I&&\"visible\"",
-    "!=q.x||\nS&&\"visible\"!=q.y){I=d(a);S=e.bottom<x.top-I.y;if(e.right<x.",
-    "left-I.x&&\"visible\"!=q.x||S&&\"visible\"!=q.x)return Z;e=Rb(a);return",
-    " e==Z?Z:\"scroll\"}I=e.left>=x.left+x.width;x=e.top>=x.top+x.height;if(",
-    "I&&\"hidden\"==q.x||x&&\"hidden\"==q.y)return Z;if(I&&\"visible\"!=q.x|",
-    "|x&&\"visible\"!=q.y){if(D&&(q=d(a),e.left>=g.scrollWidth-q.x||e.right>",
-    "=g.scrollHeight-q.y))return Z;e=Rb(a);return e==Z?Z:\"scroll\"}}}return",
-    "\"none\"}\nfunction Qb(a){var b=Sb(a);if(b)return b.rect;if(z(a,\"HTML",
-    "\"))return a=y(a),a=((a?a.parentWindow||a.defaultView:window)||window).",
-    "document,a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=new ",
-    "za(a.clientWidth,a.clientHeight),new X(0,0,a.width,a.height);try{var c=",
-    "a.getBoundingClientRect()}catch(d){return new X(0,0,0,0)}return new X(c",
-    ".left,c.top,c.right-c.left,c.bottom-c.top)}\nfunction Sb(a){var b=z(a,",
-    "\"MAP\");if(!b&&!z(a,\"AREA\"))return null;var c=b?a:z(a.parentNode,\"M",
-    "AP\")?a.parentNode:null,d=null,e=null;c&&c.name&&(d=W.pa('/descendant::",
-    "*[@usemap = \"#'+c.name+'\"]',y(c)))&&(e=Qb(d),b||\"default\"==a.shape.",
-    "toLowerCase()||(a=Wb(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.m",
-    "in(Math.max(a.top,0),e.height),e=new X(b+e.left,c+e.top,Math.min(a.widt",
-    "h,e.width-b),Math.min(a.height,e.height-c))));return{Z:d,rect:e||new X(",
-    "0,0,0,0)}}\nfunction Wb(a){var b=a.shape.toLowerCase();a=a.coords.split",
-    "(\",\");if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new X(b,c",
-    ",a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new X(a[0]-",
-    "b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=b",
-    ",e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Math",
-    ".min(c,a[f+1]),e=Math.max(e,a[f+1]);return new X(b,c,d-b,e-c)}return ne",
-    "w X(0,0,0,0)}function Vb(a){a=Qb(a);return new Lb(a.top,a.left+a.width,",
-    "a.top+a.height,a.left)}\nfunction Tb(a){var b=1,c=Y(a,\"opacity\");c&&(",
-    "b=Number(c));(a=Nb(a))&&(b*=Tb(a));return b};var Xb=\"function\"===type",
-    "of ShadowRoot;function Yb(a,b,c){if(!Ub(a,c))return!1;if(Xb){for(;a.par",
-    "entNode;)a=a.parentNode;if(a instanceof ShadowRoot)return Yb(a.host,b)}",
-    "return!0};ba(\"_\",Yb);; return this._.apply(null,arguments);}.apply({n",
-    "avigator:typeof window!='undefined'?window.navigator:null,document:type",
-    "of window!='undefined'?window.document:null}, arguments);}",
+    "function Ub(a,b){function c(a){if(z(a)&&\"none\"==Y(a,\"display\"))retu",
+    "rn!1;var b;(b=a.parentNode)&&b.shadowRoot&&void 0!==a.assignedSlot?b=a.",
+    "assignedSlot?a.assignedSlot.parentNode:null:a.getDestinationInsertionPo",
+    "ints&&(a=a.getDestinationInsertionPoints(),0<a.length&&(b=a[a.length-1]",
+    "));return Mb&&b instanceof ShadowRoot||b&&(9==b.nodeType||11==b.nodeTyp",
+    "e)?!0:!!b&&c(b)}return Pb(a,!!b,c)}var Z=\"hidden\";\nfunction Rb(a){fu",
+    "nction b(a){function b(a){return a==g?!0:0==Y(a,\"display\").lastIndexO",
+    "f(\"inline\",0)||\"absolute\"==c&&\"static\"==Y(a,\"position\")?!1:!0}v",
+    "ar c=Y(a,\"position\");if(\"fixed\"==c)return D=!0,a==g?null:g;for(a=Nb",
+    "(a);a&&!b(a);)a=Nb(a);return a}function c(a){var b=a;if(\"visible\"==w)",
+    "if(a==g&&l)b=l;else if(a==l)return{x:\"visible\",y:\"visible\"};b={x:Y(",
+    "b,\"overflow-x\"),y:Y(b,\"overflow-y\")};a==g&&(b.x=\"visible\"==b.x?\"",
+    "auto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);return b}function d(a){if",
+    "(a==g){var b=(new Ha(f)).H;\na=b.scrollingElement?b.scrollingElement:b.",
+    "body||b.documentElement;b=b.parentWindow||b.defaultView;a=new v(b.pageX",
+    "Offset||a.scrollLeft,b.pageYOffset||a.scrollTop)}else a=new v(a.scrollL",
+    "eft,a.scrollTop);return a}var e=Vb(a);var f=x(a),g=f.documentElement,l=",
+    "f.body,w=Y(g,\"overflow\"),D;for(a=b(a);a;a=b(a)){var q=c(a);if(\"visib",
+    "le\"!=q.x||\"visible\"!=q.y){var y=Qb(a);if(0==y.width||0==y.height)ret",
+    "urn Z;var H=e.right<y.left,S=e.bottom<y.top;if(H&&\"hidden\"==q.x||S&&",
+    "\"hidden\"==q.y)return Z;if(H&&\"visible\"!=q.x||\nS&&\"visible\"!=q.y)",
+    "{H=d(a);S=e.bottom<y.top-H.y;if(e.right<y.left-H.x&&\"visible\"!=q.x||S",
+    "&&\"visible\"!=q.x)return Z;e=Rb(a);return e==Z?Z:\"scroll\"}H=e.left>=",
+    "y.left+y.width;y=e.top>=y.top+y.height;if(H&&\"hidden\"==q.x||y&&\"hidd",
+    "en\"==q.y)return Z;if(H&&\"visible\"!=q.x||y&&\"visible\"!=q.y){if(D&&(",
+    "q=d(a),e.left>=g.scrollWidth-q.x||e.right>=g.scrollHeight-q.y))return Z",
+    ";e=Rb(a);return e==Z?Z:\"scroll\"}}}return\"none\"}\nfunction Qb(a){var",
+    " b=Sb(a);if(b)return b.rect;if(z(a,\"HTML\"))return a=x(a),a=((a?a.pare",
+    "ntWindow||a.defaultView:window)||window).document,a=\"CSS1Compat\"==a.c",
+    "ompatMode?a.documentElement:a.body,a=new za(a.clientWidth,a.clientHeigh",
+    "t),new X(0,0,a.width,a.height);try{var c=a.getBoundingClientRect()}catc",
+    "h(d){return new X(0,0,0,0)}return new X(c.left,c.top,c.right-c.left,c.b",
+    "ottom-c.top)}\nfunction Sb(a){var b=z(a,\"MAP\");if(!b&&!z(a,\"AREA\"))",
+    "return null;var c=b?a:z(a.parentNode,\"MAP\")?a.parentNode:null,d=null,",
+    "e=null;c&&c.name&&(d=W.pa('/descendant::*[@usemap = \"#'+c.name+'\"]',x",
+    "(c)))&&(e=Qb(d),b||\"default\"==a.shape.toLowerCase()||(a=Wb(a),b=Math.",
+    "min(Math.max(a.left,0),e.width),c=Math.min(Math.max(a.top,0),e.height),",
+    "e=new X(b+e.left,c+e.top,Math.min(a.width,e.width-b),Math.min(a.height,",
+    "e.height-c))));return{Z:d,rect:e||new X(0,0,0,0)}}\nfunction Wb(a){var ",
+    "b=a.shape.toLowerCase();a=a.coords.split(\",\");if(\"rect\"==b&&4==a.le",
+    "ngth){var b=a[0],c=a[1];return new X(b,c,a[2]-b,a[3]-c)}if(\"circle\"==",
+    "b&&3==a.length)return b=a[2],new X(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==",
+    "b&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Ma",
+    "th.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f",
+    "+1]);return new X(b,c,d-b,e-c)}return new X(0,0,0,0)}function Vb(a){a=Q",
+    "b(a);return new Lb(a.top,a.left+a.width,a.top+a.height,a.left)}\nfuncti",
+    "on Tb(a){var b=1,c=Y(a,\"opacity\");c&&(b=Number(c));(a=Nb(a))&&(b*=Tb(",
+    "a));return b};var Xb=\"function\"===typeof ShadowRoot;function Yb(a,b,c",
+    "){if(!Ub(a,c))return!1;if(Xb){for(;a.parentNode;)a=a.parentNode;if(a in",
+    "stanceof ShadowRoot)return Yb(a.host,b)}return!0};ba(\"_\",Yb);; return",
+    " this._.apply(null,arguments);}.apply({navigator:typeof window!='undefi",
+    "ned'?window.navigator:null,document:typeof window!='undefined'?window.d",
+    "ocument:null}, arguments);}",
     NULL
 };
 
@@ -7792,31 +7801,32 @@
     "\"string\"!==typeof b&&(b=b.toString());return!!a&&1==a.nodeType&&(!b||",
     "a.tagName.toUpperCase()==b)}function u(a){return t(a,\"OPTION\")?!0:t(a",
     ",\"INPUT\")?(a=a.type.toLowerCase(),\"checkbox\"==a||\"radio\"==a):!1};",
-    "var v={\"class\":\"className\",readonly:\"readOnly\"},w=\"async autofoc",
-    "us autoplay checked compact complete controls declare defaultchecked de",
-    "faultselected defer disabled draggable ended formnovalidate hidden inde",
-    "terminate iscontenteditable ismap itemscope loop multiple muted nohref ",
-    "noresize noshade novalidate nowrap open paused pubdate readonly require",
-    "d reversed scoped seamless seeking selected spellcheck truespeed willva",
-    "lidate\".split(\" \");function x(a,b){var c=b.toLowerCase();if(\"style",
-    "\"==c)return(b=a.style)&&!d(b)&&(b=b.cssText),b;if((\"selected\"==c||\"",
-    "checked\"==c)&&u(a)){if(!u(a))throw new g(15,\"Element is not selectabl",
-    "e\");b=\"selected\";var e=a.type&&a.type.toLowerCase();if(\"checkbox\"=",
-    "=e||\"radio\"==e)b=\"checked\";return a[b]?\"true\":null}var f=t(a,\"A",
-    "\");if(t(a,\"IMG\")&&\"src\"==c||f&&\"href\"==c)return(b=p(a,c))&&(b=a[",
-    "c]),b;if(\"spellcheck\"==c){b=p(a,c);if(null!==b){if(\"false\"==b.toLow",
-    "erCase())return\"false\";if(\"true\"==b.toLowerCase())return\"true\"}re",
-    "turn a[c]+\n\"\"}f=v[b]||b;a:if(d(w))c=d(c)&&1==c.length?w.indexOf(c,0)",
-    ":-1;else{for(var l=0;l<w.length;l++)if(l in w&&w[l]===c){c=l;break a}c=",
-    "-1}if(0<=c)return(b=null!==p(a,b)||a[f])?\"true\":null;try{e=a[f]}catch",
-    "(m){}(c=null==e)||(c=typeof e,c=\"object\"==c&&null!=e||\"function\"==c",
-    ");b=c?p(a,b):e;return null!=b?b.toString():null}var y=[\"_\"],z=this;y[",
-    "0]in z||!z.execScript||z.execScript(\"var \"+y[0]);\nfor(var A;y.length",
-    "&&(A=y.shift());){var B;if(B=!y.length)B=void 0!==x;B?z[A]=x:z=z[A]&&z[",
-    "A]!==Object.prototype[A]?z[A]:z[A]={}};; return this._.apply(null,argum",
-    "ents);}.apply({navigator:typeof window!='undefined'?window.navigator:nu",
-    "ll,document:typeof window!='undefined'?window.document:null}, arguments",
-    ");}",
+    "var v={\"class\":\"className\",readonly:\"readOnly\"},w=\"allowfullscre",
+    "en allowpaymentrequest allowusermedia async autofocus autoplay checked ",
+    "compact complete controls declare default defaultchecked defaultselecte",
+    "d defer disabled ended formnovalidate hidden indeterminate iscontentedi",
+    "table ismap itemscope loop multiple muted nohref nomodule noresize nosh",
+    "ade novalidate nowrap open paused playsinline pubdate readonly required",
+    " reversed scoped seamless seeking selected truespeed typemustmatch will",
+    "validate\".split(\" \");function x(a,b){var c=b.toLowerCase();if(\"styl",
+    "e\"==c)return(b=a.style)&&!d(b)&&(b=b.cssText),b;if((\"selected\"==c||",
+    "\"checked\"==c)&&u(a)){if(!u(a))throw new g(15,\"Element is not selecta",
+    "ble\");b=\"selected\";var e=a.type&&a.type.toLowerCase();if(\"checkbox",
+    "\"==e||\"radio\"==e)b=\"checked\";return a[b]?\"true\":null}var f=t(a,",
+    "\"A\");if(t(a,\"IMG\")&&\"src\"==c||f&&\"href\"==c)return(b=p(a,c))&&(b",
+    "=a[c]),b;if(\"spellcheck\"==c){b=p(a,c);if(null!==b){if(\"false\"==b.to",
+    "LowerCase())return\"false\";if(\"true\"==b.toLowerCase())return\"true\"",
+    "}return a[c]+\n\"\"}f=v[b]||b;a:if(d(w))c=d(c)&&1==c.length?w.indexOf(c",
+    ",0):-1;else{for(var l=0;l<w.length;l++)if(l in w&&w[l]===c){c=l;break a",
+    "}c=-1}if(0<=c)return(b=null!==p(a,b)||a[f])?\"true\":null;try{e=a[f]}ca",
+    "tch(m){}(c=null==e)||(c=typeof e,c=\"object\"==c&&null!=e||\"function\"",
+    "==c);b=c?p(a,b):e;return null!=b?b.toString():null}var y=[\"_\"],z=this",
+    ";y[0]in z||!z.execScript||z.execScript(\"var \"+y[0]);\nfor(var A;y.len",
+    "gth&&(A=y.shift());){var B;if(B=!y.length)B=void 0!==x;B?z[A]=x:z=z[A]&",
+    "&z[A]!==Object.prototype[A]?z[A]:z[A]={}};; return this._.apply(null,ar",
+    "guments);}.apply({navigator:typeof window!='undefined'?window.navigator",
+    ":null,document:typeof window!='undefined'?window.document:null}, argume",
+    "nts);}",
     NULL
 };
 
@@ -8156,7 +8166,7 @@
     "rn l(b)&&1==b.length?a.indexOf(b,0):-1;for(var c=0;c<a.length;c++)if(c ",
     "in a&&a[c]===b)return c;return-1}function q(a,b){for(var c=a.length,d=l",
     "(a)?a.split(\"\"):a,e=0;e<c;e++)e in d&&b.call(void 0,d[e],e,a)}functio",
-    "n t(a,b,c){var d=c;q(a,function(c,f){d=b.call(void 0,d,c,f,a)});return ",
+    "n r(a,b,c){var d=c;q(a,function(c,f){d=b.call(void 0,d,c,f,a)});return ",
     "d}function oa(a,b){for(var c=a.length,d=l(a)?a.split(\"\"):a,e=0;e<c;e+",
     "+)if(e in d&&b.call(void 0,d[e],e,a))return!0;return!1}\nfunction pa(a,",
     "b){for(var c=a.length,d=l(a)?a.split(\"\"):a,e=0;e<c;e++)if(e in d&&!b.",
@@ -8215,13 +8225,13 @@
     "9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/,wa=/^#(?:[0-9a-f]{3}){1,2}$/i,xa=/",
     "^(?:rgba)?\\((\\d{1,3}),\\s?(\\d{1,3}),\\s?(\\d{1,3}),\\s?(0|1|0\\.\\d*",
     ")\\)$/i,ya=/^(?:rgb)?\\((0|[1-9]\\d{0,2}),\\s?(0|[1-9]\\d{0,2}),\\s?(0|",
-    "[1-9]\\d{0,2})\\)$/i;function za(a,b){this.code=a;this.state=u[a]||Aa;t",
+    "[1-9]\\d{0,2})\\)$/i;function za(a,b){this.code=a;this.state=u[a]||Ba;t",
     "his.message=b||\"\";a=this.state.replace(/((?:^|\\s+)[a-z])/g,function(",
     "a){return a.toUpperCase().replace(/^[\\s\\xa0]+/g,\"\")});b=a.length-5;",
     "if(0>b||a.indexOf(\"Error\",b)!=b)a+=\"Error\";this.name=a;a=Error(this",
-    ".message);a.name=this.name;this.stack=a.stack||\"\"}p(za,Error);var Aa=",
+    ".message);a.name=this.name;this.stack=a.stack||\"\"}p(za,Error);var Ba=",
     "\"unknown error\",u={15:\"element not selectable\",11:\"element not vis",
-    "ible\"};u[31]=Aa;u[30]=Aa;u[24]=\"invalid cookie domain\";u[29]=\"inval",
+    "ible\"};u[31]=Ba;u[30]=Ba;u[24]=\"invalid cookie domain\";u[29]=\"inval",
     "id element coordinates\";u[12]=\"invalid element state\";\nu[32]=\"inva",
     "lid selector\";u[51]=\"invalid selector\";u[52]=\"invalid selector\";u[",
     "17]=\"javascript error\";u[405]=\"unsupported operation\";u[34]=\"move ",
@@ -8229,7 +8239,7 @@
     ";u[8]=\"no such frame\";u[23]=\"no such window\";u[28]=\"script timeout",
     "\";u[33]=\"session not created\";u[10]=\"stale element reference\";u[21",
     "]=\"timeout\";u[25]=\"unable to set cookie\";u[26]=\"unexpected alert o",
-    "pen\";u[13]=Aa;u[9]=\"unknown command\";za.prototype.toString=function(",
+    "pen\";u[13]=Ba;u[9]=\"unknown command\";za.prototype.toString=function(",
     "){return this.name+\": \"+this.message};var Ca;a:{var Da=aa.navigator;i",
     "f(Da){var Ea=Da.userAgent;if(Ea){Ca=Ea;break a}}Ca=\"\"};function Fa(a)",
     "{var b=Ga;Object.prototype.hasOwnProperty.call(b,\"528\")||(b[\"528\"]=",
@@ -8404,7 +8414,7 @@
     "b.length||a.na&&!!b.length||oa(b,function(a){return a.l}))}\np(rb,H);rb",
     ".prototype.evaluate=function(a){return this.N.u.apply(null,qa(a,this.T)",
     ")};rb.prototype.toString=function(){var a=\"Function: \"+this.N;if(this",
-    ".T.length)var b=t(this.T,function(a,b){return a+I(b)},\"Arguments:\"),a",
+    ".T.length)var b=r(this.T,function(a,b){return a+I(b)},\"Arguments:\"),a",
     "=a+I(b);return a};function sb(a,b,c,d,e,f,h,m,v){this.m=a;this.i=b;this",
     ".A=c;this.oa=d;this.na=e;this.u=f;this.ga=h;this.W=k(m)?m:h;this.qa=!!v",
     "}sb.prototype.toString=function(){return this.m};var tb={};\nfunction O",
@@ -8412,7 +8422,7 @@
     "y created: \"+a+\".\");tb[a]=new sb(a,b,c,d,!1,e,f,h,m)}O(\"boolean\",2",
     ",!1,!1,function(a,b){return M(b,a)},1);O(\"ceiling\",1,!1,!1,function(a",
     ",b){return Math.ceil(J(b,a))},1);O(\"concat\",3,!1,!1,function(a,b){ret",
-    "urn t(sa(arguments,1),function(b,d){return b+K(d,a)},\"\")},2,null);O(",
+    "urn r(sa(arguments,1),function(b,d){return b+K(d,a)},\"\")},2,null);O(",
     "\"contains\",2,!1,!1,function(a,b,c){b=K(b,a);a=K(c,a);return-1!=b.inde",
     "xOf(a)},2);O(\"count\",1,!1,!1,function(a,b){return b.evaluate(a).v()},",
     "1,1,!0);\nO(\"false\",2,!1,!1,function(){return!1},0);O(\"floor\",1,!1,",
@@ -8485,7 +8495,7 @@
     "e h=f.next(),b=e.evaluate(new z(h));else{for(h=f.next();(b=f.next())&&(",
     "!h.contains||h.contains(b))&&b.compareDocumentPosition(h)&8;h=b);b=e.ev",
     "aluate(new z(h))}}return b};\nyb.prototype.toString=function(){var a=\"",
-    "Path Expression:\"+I(this.ca);if(this.L.length){var b=t(this.L,function",
+    "Path Expression:\"+I(this.ca);if(this.L.length){var b=r(this.L,function",
     "(a,b){return a+I(b)},\"Steps:\");a+=I(b)}return a};function P(a,b){this",
     ".f=a;this.G=!!b}function qb(a,b,c){for(c=c||0;c<a.f.length;c++)for(var ",
     "d=a.f[c],e=b.iterator(),f=b.v(),h,m=0;h=e.next();m++){var v=a.G?f-m:m+1",
@@ -8496,7 +8506,7 @@
     "length?this.f[0].C():null};\nP.prototype.h=function(){for(var a=0;a<thi",
     "s.f.length;a++){var b=this.f[a];if(b.h()||1==b.i||0==b.i)return!0}retur",
     "n!1};P.prototype.v=function(){return this.f.length};P.prototype.toStrin",
-    "g=function(){return t(this.f,function(a,b){return a+I(b)},\"Predicates:",
+    "g=function(){return r(this.f,function(a,b){return a+I(b)},\"Predicates:",
     "\")};function Q(a,b,c,d){H.call(this,4);this.B=a;this.S=b;this.f=c||new",
     " P([]);this.U=!!d;b=this.f.C();a.va&&b&&(this.K={name:b.name,I:b.I});th",
     "is.A=this.f.h()}p(Q,H);\nQ.prototype.evaluate=function(a){var b=a.s,c=t",
@@ -8507,7 +8517,7 @@
     ";else a=this.u(a.s,d,e,f);return a};Q.prototype.u=function(a,b,c,d){a=t",
     "his.B.N(this.S,a,b,c);return a=qb(this.f,a,d)};\nQ.prototype.toString=f",
     "unction(){var a=\"Step:\"+I(\"Operator: \"+(this.U?\"//\":\"/\"));this.",
-    "B.m&&(a+=I(\"Axis: \"+this.B));a+=I(this.S);if(this.f.v()){var b=t(this",
+    "B.m&&(a+=I(\"Axis: \"+this.B));a+=I(this.S);if(this.f.v()){var b=r(this",
     ".f.f,function(a,b){return a+I(b)},\"Predicates:\");a+=I(b)}return a};fu",
     "nction Hb(a,b,c,d){this.m=a;this.N=b;this.G=c;this.va=d}Hb.prototype.to",
     "String=function(){return this.m};var Ib={};function R(a,b,c,d){if(Ib.ha",
@@ -8532,7 +8542,7 @@
     "entNode;a.matches(b)&&c.add(b);return c},!1),Eb=R(\"preceding\",functio",
     "n(a,b,c,d){var e=new F,f=[];do f.unshift(b);while(b=b.parentNode);for(v",
     "ar h=1,m=f.length;h<m;h++){var v=[];for(b=f[h];b=b.previousSibling;)v.u",
-    "nshift(b);for(var C=0,r=v.length;C<r;C++)b=v[C],E(b,c,d)&&a.matches(b)&",
+    "nshift(b);for(var C=0,t=v.length;C<t;C++)b=v[C],E(b,c,d)&&a.matches(b)&",
     "&e.add(b),e=ab(a,b,c,d,e)}return e},!0,!0);\nR(\"preceding-sibling\",fu",
     "nction(a,b){for(var c=new F;b=b.previousSibling;)a.matches(b)&&c.unshif",
     "t(b);return c},!0);var Kb=R(\"self\",function(a,b){var c=new F;a.matche",
@@ -8544,7 +8554,7 @@
     "l}))}p(Mb,H);Mb.prototype.evaluate=function(a){var b=new F;q(this.R,fun",
     "ction(c){c=c.evaluate(a);if(!(c instanceof F))throw Error(\"Path expres",
     "sion must evaluate to NodeSet.\");b=eb(b,c)});return b};Mb.prototype.to",
-    "String=function(){return t(this.R,function(a,b){return a+I(b)},\"Union ",
+    "String=function(){return r(this.R,function(a,b){return a+I(b)},\"Union ",
     "Expression:\")};function Nb(a,b){this.a=a;this.ra=b}function Ob(a){for(",
     "var b,c=[];;){S(a,\"Missing right hand side of binary expression.\");b=",
     "Pb(a);var d=a.a.next();if(!d)break;var e=(d=ob[d]||null)&&d.ha;if(!e){a",
@@ -8630,13 +8640,13 @@
     "c){var d=x(a);if(!d.documentElement)return null;try{for(var e=d.createN",
     "SResolver?d.createNSResolver(d.documentElement):V.Z,f={},h=d.getElement",
     "sByTagName(\"*\"),m=0;m<h.length;++m){var v=h[m],C=v.namespaceURI;if(C&",
-    "&!f[C]){var r=v.lookupPrefix(C);if(!r)var A=C.match(\".*/(\\\\w+)/?$\")",
-    ",r=A?A[1]:\"xhtml\";f[C]=r}}var L={},T;for(T in f)L[f[T]]=T;e=function(",
-    "a){return L[a]||null};try{return d.evaluate(b,a,e,c,null)}catch(Ba){if(",
-    "\"TypeError\"===Ba.name)return e=d.createNSResolver?d.createNSResolver(",
-    "d.documentElement):\nV.Z,d.evaluate(b,a,e,c,null);throw Ba;}}catch(Ba){",
+    "&!f[C]){var t=v.lookupPrefix(C);if(!t)var A=C.match(\".*/(\\\\w+)/?$\")",
+    ",t=A?A[1]:\"xhtml\";f[C]=t}}var L={},T;for(T in f)L[f[T]]=T;e=function(",
+    "a){return L[a]||null};try{return d.evaluate(b,a,e,c,null)}catch(Aa){if(",
+    "\"TypeError\"===Aa.name)return e=d.createNSResolver?d.createNSResolver(",
+    "d.documentElement):\nV.Z,d.evaluate(b,a,e,c,null);throw Aa;}}catch(Aa){",
     "throw new za(32,\"Unable to locate an element with the xpath expression",
-    " \"+b+\" because of the following error:\\n\"+Ba);}};V.$=function(a,b){",
+    " \"+b+\" because of the following error:\\n\"+Aa);}};V.$=function(a,b){",
     "if(!a||1!=a.nodeType)throw new za(32,'The result of the xpath expressio",
     "n \"'+b+'\" is: '+a+\". It should be an element.\");};\nV.ua=function(a",
     ",b){var c=function(){var c=V.u(b,a,9);return c?c.singleNodeValue||null:",
@@ -8713,136 +8723,137 @@
     ".width&&0<f.rect.height&&ec(f.da,b,c);if(y(a,\"INPUT\")&&\"hidden\"==a.",
     "type.toLowerCase()||y(a,\"NOSCRIPT\"))return!1;f=X(a,\"visibility\");re",
     "turn\"collapse\"!=f&&\"hidden\"!=f&&c(a)&&(b||0!=ic(a))&&d(a)?!e(a):!1}",
-    "\nfunction jc(a){var b=bc?function(c){if(\"none\"==X(c,\"display\"))ret",
-    "urn!1;do{var d=c.parentNode;if(c.getDestinationInsertionPoints){var e=c",
-    ".getDestinationInsertionPoints();0<e.length&&(d=e[e.length-1])}if(d ins",
-    "tanceof ShadowRoot)return!0;!d||9!=d.nodeType&&11!=d.nodeType||(d=null)",
-    "}while(a&&1!=a.nodeType);return!d||b(d)}:function(a){if(\"none\"==X(a,",
-    "\"display\"))return!1;a=cc(a);return!a||b(a)};return ec(a,!1,b)}var Y=",
-    "\"hidden\";\nfunction gc(a){function b(a){function b(a){return a==h?!0:",
-    "0==X(a,\"display\").lastIndexOf(\"inline\",0)||\"absolute\"==c&&\"stati",
-    "c\"==X(a,\"position\")?!1:!0}var c=X(a,\"position\");if(\"fixed\"==c)re",
-    "turn C=!0,a==h?null:h;for(a=cc(a);a&&!b(a);)a=cc(a);return a}function c",
-    "(a){var b=a;if(\"visible\"==v)if(a==h&&m)b=m;else if(a==m)return{x:\"vi",
-    "sible\",y:\"visible\"};b={x:X(b,\"overflow-x\"),y:X(b,\"overflow-y\")};",
-    "a==h&&(b.x=\"visible\"==b.x?\"auto\":b.x,b.y=\"visible\"==b.y?\"auto\":",
-    "b.y);return b}function d(a){if(a==h){var b=(new Wa(f)).M;\na=b.scrollin",
-    "gElement?b.scrollingElement:b.body||b.documentElement;b=b.parentWindow|",
-    "|b.defaultView;a=new w(b.pageXOffset||a.scrollLeft,b.pageYOffset||a.scr",
-    "ollTop)}else a=new w(a.scrollLeft,a.scrollTop);return a}var e=kc(a);var",
-    " f=x(a),h=f.documentElement,m=f.body,v=X(h,\"overflow\"),C;for(a=b(a);a",
-    ";a=b(a)){var r=c(a);if(\"visible\"!=r.x||\"visible\"!=r.y){var A=fc(a);",
-    "if(0==A.width||0==A.height)return Y;var L=e.right<A.left,T=e.bottom<A.t",
-    "op;if(L&&\"hidden\"==r.x||T&&\"hidden\"==r.y)return Y;if(L&&\"visible\"",
-    "!=r.x||\nT&&\"visible\"!=r.y){L=d(a);T=e.bottom<A.top-L.y;if(e.right<A.",
-    "left-L.x&&\"visible\"!=r.x||T&&\"visible\"!=r.x)return Y;e=gc(a);return",
-    " e==Y?Y:\"scroll\"}L=e.left>=A.left+A.width;A=e.top>=A.top+A.height;if(",
-    "L&&\"hidden\"==r.x||A&&\"hidden\"==r.y)return Y;if(L&&\"visible\"!=r.x|",
-    "|A&&\"visible\"!=r.y){if(C&&(r=d(a),e.left>=h.scrollWidth-r.x||e.right>",
-    "=h.scrollHeight-r.y))return Y;e=gc(a);return e==Y?Y:\"scroll\"}}}return",
-    "\"none\"}\nfunction fc(a){var b=hc(a);if(b)return b.rect;if(y(a,\"HTML",
-    "\"))return a=x(a),a=((a?a.parentWindow||a.defaultView:window)||window).",
-    "document,a=\"CSS1Compat\"==a.compatMode?a.documentElement:a.body,a=new ",
-    "Na(a.clientWidth,a.clientHeight),new W(0,0,a.width,a.height);try{var c=",
-    "a.getBoundingClientRect()}catch(d){return new W(0,0,0,0)}return new W(c",
-    ".left,c.top,c.right-c.left,c.bottom-c.top)}\nfunction hc(a){var b=y(a,",
-    "\"MAP\");if(!b&&!y(a,\"AREA\"))return null;var c=b?a:y(a.parentNode,\"M",
-    "AP\")?a.parentNode:null,d=null,e=null;c&&c.name&&(d=V.ua('/descendant::",
-    "*[@usemap = \"#'+c.name+'\"]',x(c)))&&(e=fc(d),b||\"default\"==a.shape.",
-    "toLowerCase()||(a=lc(a),b=Math.min(Math.max(a.left,0),e.width),c=Math.m",
-    "in(Math.max(a.top,0),e.height),e=new W(b+e.left,c+e.top,Math.min(a.widt",
-    "h,e.width-b),Math.min(a.height,e.height-c))));return{da:d,rect:e||new W",
-    "(0,0,0,0)}}\nfunction lc(a){var b=a.shape.toLowerCase();a=a.coords.spli",
-    "t(\",\");if(\"rect\"==b&&4==a.length){var b=a[0],c=a[1];return new W(b,",
-    "c,a[2]-b,a[3]-c)}if(\"circle\"==b&&3==a.length)return b=a[2],new W(a[0]",
-    "-b,a[1]-b,2*b,2*b);if(\"poly\"==b&&2<a.length){for(var b=a[0],c=a[1],d=",
-    "b,e=c,f=2;f+1<a.length;f+=2)b=Math.min(b,a[f]),d=Math.max(d,a[f]),c=Mat",
-    "h.min(c,a[f+1]),e=Math.max(e,a[f+1]);return new W(b,c,d-b,e-c)}return n",
-    "ew W(0,0,0,0)}function kc(a){a=fc(a);return new ac(a.top,a.left+a.width",
-    ",a.top+a.height,a.left)}\nfunction mc(a){return a.replace(/^[^\\S\\xa0]",
-    "+|[^\\S\\xa0]+$/g,\"\")}\nfunction nc(a,b,c){if(y(a,\"BR\"))b.push(\"\"",
-    ");else{var d=y(a,\"TD\"),e=X(a,\"display\"),f=!d&&!(0<=na(oc,e)),h=k(a.",
-    "previousElementSibling)?a.previousElementSibling:Qa(a.previousSibling),",
-    "h=h?X(h,\"display\"):\"\",m=X(a,\"float\")||X(a,\"cssFloat\")||X(a,\"st",
-    "yleFloat\");!f||\"run-in\"==h&&\"none\"==m||/^[\\s\\xa0]*$/.test(b[b.le",
-    "ngth-1]||\"\")||b.push(\"\");var v=jc(a),C=null,r=null;v&&(C=X(a,\"whit",
-    "e-space\"),r=X(a,\"text-transform\"));q(a.childNodes,function(a){c(a,b,",
-    "v,C,r)});a=b[b.length-1]||\"\";!d&&\"table-cell\"!=e||!a||ja(a)||(b[b.l",
-    "ength-\n1]+=\" \");f&&\"run-in\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(",
-    "\"\")}}function pc(a,b){nc(a,b,function(a,b,e,f,h){3==a.nodeType&&e?qc(",
-    "a,b,f,h):y(a)&&pc(a,b)})}var oc=\"inline inline-block inline-table none",
-    " table-cell table-column table-column-group\".split(\" \");\nfunction q",
-    "c(a,b,c,d){a=a.nodeValue.replace(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.r",
-    "eplace(/(\\r\\n|\\r|\\n)/g,\"\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a",
-    ".replace(/\\n/g,\" \");a=\"pre\"==c||\"pre-wrap\"==c?a.replace(/[ \\f",
-    "\\t\\v\\u2028\\u2029]/g,\"\\u00a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u",
-    "2029]+/g,\" \");\"capitalize\"==d?a=a.replace(/(^|\\s)(\\S)/g,function(",
-    "a,b,c){return b+c.toUpperCase()}):\"uppercase\"==d?a=a.toUpperCase():\"",
-    "lowercase\"==d&&(a=a.toLowerCase());c=b.pop()||\"\";ja(c)&&0==a.lastInd",
-    "exOf(\" \",0)&&(a=a.substr(1));b.push(c+a)}\nfunction ic(a){var b=1,c=X",
-    "(a,\"opacity\");c&&(b=Number(c));(a=cc(a))&&(b*=ic(a));return b}\nfunct",
-    "ion rc(a,b,c,d,e){var f;if(3==a.nodeType&&c)qc(a,b,d,e);else if(y(a))if",
-    "(y(a,\"CONTENT\")){for(f=a;f.parentNode;)f=f.parentNode;f instanceof Sh",
-    "adowRoot?q(a.getDistributedNodes(),function(a){rc(a,b,c,d,e)}):sc(a,b)}",
-    "else if(y(a,\"SHADOW\")){for(f=a;f.parentNode;)f=f.parentNode;if(f inst",
-    "anceof ShadowRoot&&(a=f))for(a=a.olderShadowRoot;a;)q(a.childNodes,func",
-    "tion(a){rc(a,b,c,d,e)}),a=a.olderShadowRoot}else sc(a,b)}\nfunction sc(",
-    "a,b){a.shadowRoot&&q(a.shadowRoot.childNodes,function(a){rc(a,b,!0,null",
-    ",null)});nc(a,b,function(a,b,e,f,h){var c=null;1==a.nodeType?c=a:3==a.n",
-    "odeType&&(c=a);null!=c&&c.getDestinationInsertionPoints&&0<c.getDestina",
-    "tionInsertionPoints().length||rc(a,b,e,f,h)})};Ma();Ma();function tc(a,",
-    "b){this.w={};this.g=[];this.F=0;var c=arguments.length;if(1<c){if(c%2)t",
-    "hrow Error(\"Uneven number of arguments\");for(var d=0;d<c;d+=2)this.se",
-    "t(arguments[d],arguments[d+1])}else a&&this.addAll(a)}function uc(a){vc",
-    "(a);return a.g.concat()}g=tc.prototype;g.clear=function(){this.w={};thi",
-    "s.F=this.g.length=0};g.remove=function(a){return Object.prototype.hasOw",
-    "nProperty.call(this.w,a)?(delete this.w[a],this.F--,this.g.length>2*thi",
-    "s.F&&vc(this),!0):!1};\nfunction vc(a){var b,c;if(a.F!=a.g.length){for(",
-    "b=c=0;c<a.g.length;){var d=a.g[c];Object.prototype.hasOwnProperty.call(",
-    "a.w,d)&&(a.g[b++]=d);c++}a.g.length=b}if(a.F!=a.g.length){var e={};for(",
-    "b=c=0;c<a.g.length;)d=a.g[c],Object.prototype.hasOwnProperty.call(e,d)|",
-    "|(a.g[b++]=d,e[d]=1),c++;a.g.length=b}}g.get=function(a,b){return Objec",
-    "t.prototype.hasOwnProperty.call(this.w,a)?this.w[a]:b};g.set=function(a",
-    ",b){Object.prototype.hasOwnProperty.call(this.w,a)||(this.F++,this.g.pu",
-    "sh(a));this.w[a]=b};\ng.addAll=function(a){if(a instanceof tc){var b=uc",
-    "(a);vc(a);for(var c=[],d=0;d<a.g.length;d++)c.push(a.w[a.g[d]]);a=c}els",
-    "e{b=[];var d=0;for(e in a)b[d++]=e;d=[];var e=0;for(c in a)d[e++]=a[c];",
-    "a=d}for(c=0;c<b.length;c++)this.set(b[c],a[c])};g.forEach=function(a,b)",
-    "{for(var c=uc(this),d=0;d<c.length;d++){var e=c[d],f=this.get(e);a.call",
-    "(b,f,e,this)}};g.clone=function(){return new tc(this)};var wc={};functi",
-    "on Z(a,b,c){ea(a)&&(a=a.b);a=new xc(a);!b||b in wc&&!c||(wc[b]={key:a,s",
-    "hift:!1},c&&(wc[c]={key:a,shift:!0}));return a}function xc(a){this.code",
-    "=a}Z(8);Z(9);Z(13);var yc=Z(16),zc=Z(17),Ac=Z(18);Z(19);Z(20);Z(27);Z(3",
-    "2,\" \");Z(33);Z(34);Z(35);Z(36);Z(37);Z(38);Z(39);Z(40);Z(44);Z(45);Z(",
-    "46);Z(48,\"0\",\")\");Z(49,\"1\",\"!\");Z(50,\"2\",\"@\");Z(51,\"3\",\"",
-    "#\");Z(52,\"4\",\"$\");Z(53,\"5\",\"%\");Z(54,\"6\",\"^\");Z(55,\"7\",",
-    "\"&\");Z(56,\"8\",\"*\");Z(57,\"9\",\"(\");Z(65,\"a\",\"A\");Z(66,\"b\"",
-    ",\"B\");Z(67,\"c\",\"C\");Z(68,\"d\",\"D\");\nZ(69,\"e\",\"E\");Z(70,\"",
-    "f\",\"F\");Z(71,\"g\",\"G\");Z(72,\"h\",\"H\");Z(73,\"i\",\"I\");Z(74,",
-    "\"j\",\"J\");Z(75,\"k\",\"K\");Z(76,\"l\",\"L\");Z(77,\"m\",\"M\");Z(78",
-    ",\"n\",\"N\");Z(79,\"o\",\"O\");Z(80,\"p\",\"P\");Z(81,\"q\",\"Q\");Z(8",
-    "2,\"r\",\"R\");Z(83,\"s\",\"S\");Z(84,\"t\",\"T\");Z(85,\"u\",\"U\");Z(",
-    "86,\"v\",\"V\");Z(87,\"w\",\"W\");Z(88,\"x\",\"X\");Z(89,\"y\",\"Y\");Z",
-    "(90,\"z\",\"Z\");var Bc=Z(Ia?{c:91,b:91}:Ha?{c:224,b:91}:{c:0,b:91});Z(",
-    "Ia?{c:92,b:92}:Ha?{c:224,b:93}:{c:0,b:92});Z(Ia?{c:93,b:93}:Ha?{c:0,b:0",
-    "}:{c:93,b:null});Z({c:96,b:96},\"0\");Z({c:97,b:97},\"1\");\nZ({c:98,b:",
-    "98},\"2\");Z({c:99,b:99},\"3\");Z({c:100,b:100},\"4\");Z({c:101,b:101},",
-    "\"5\");Z({c:102,b:102},\"6\");Z({c:103,b:103},\"7\");Z({c:104,b:104},\"",
-    "8\");Z({c:105,b:105},\"9\");Z({c:106,b:106},\"*\");Z({c:107,b:107},\"+",
-    "\");Z({c:109,b:109},\"-\");Z({c:110,b:110},\".\");Z({c:111,b:111},\"/\"",
-    ");Z(144);Z(112);Z(113);Z(114);Z(115);Z(116);Z(117);Z(118);Z(119);Z(120)",
-    ";Z(121);Z(122);Z(123);Z({c:107,b:187},\"=\",\"+\");Z(108,\",\");Z({c:10",
-    "9,b:189},\"-\",\"_\");Z(188,\",\",\"<\");Z(190,\".\",\">\");Z(191,\"/\"",
-    ",\"?\");Z(192,\"`\",\"~\");Z(219,\"[\",\"{\");\nZ(220,\"\\\\\",\"|\");Z",
-    "(221,\"]\",\"}\");Z({c:59,b:186},\";\",\":\");Z(222,\"'\",'\"');var Cc=",
-    "new tc;Cc.set(1,yc);Cc.set(2,zc);Cc.set(4,Ac);Cc.set(8,Bc);(function(a)",
-    "{var b=new tc;q(uc(a),function(c){b.set(a.get(c).code,c)});return b})(C",
-    "c);ba(\"_\",function(a){var b=[];bc?sc(a,b):pc(a,b);var c=b;a=c.length;",
-    "for(var b=Array(a),c=l(c)?c.split(\"\"):c,d=0;d<a;d++)d in c&&(b[d]=mc.",
-    "call(void 0,c[d]));return mc(b.join(\"\\n\")).replace(/\\xa0/g,\" \")})",
-    ";; return this._.apply(null,arguments);}.apply({navigator:typeof window",
-    "!='undefined'?window.navigator:null,document:typeof window!='undefined'",
-    "?window.document:null}, arguments);}",
+    "\nfunction jc(a){function b(a){if(y(a)&&\"none\"==X(a,\"display\"))retu",
+    "rn!1;var c;(c=a.parentNode)&&c.shadowRoot&&void 0!==a.assignedSlot?c=a.",
+    "assignedSlot?a.assignedSlot.parentNode:null:a.getDestinationInsertionPo",
+    "ints&&(a=a.getDestinationInsertionPoints(),0<a.length&&(c=a[a.length-1]",
+    "));return bc&&c instanceof ShadowRoot||c&&(9==c.nodeType||11==c.nodeTyp",
+    "e)?!0:!!c&&b(c)}return ec(a,!1,b)}var Y=\"hidden\";\nfunction gc(a){fun",
+    "ction b(a){function b(a){return a==h?!0:0==X(a,\"display\").lastIndexOf",
+    "(\"inline\",0)||\"absolute\"==c&&\"static\"==X(a,\"position\")?!1:!0}va",
+    "r c=X(a,\"position\");if(\"fixed\"==c)return C=!0,a==h?null:h;for(a=cc(",
+    "a);a&&!b(a);)a=cc(a);return a}function c(a){var b=a;if(\"visible\"==v)i",
+    "f(a==h&&m)b=m;else if(a==m)return{x:\"visible\",y:\"visible\"};b={x:X(b",
+    ",\"overflow-x\"),y:X(b,\"overflow-y\")};a==h&&(b.x=\"visible\"==b.x?\"a",
+    "uto\":b.x,b.y=\"visible\"==b.y?\"auto\":b.y);return b}function d(a){if(",
+    "a==h){var b=(new Wa(f)).M;\na=b.scrollingElement?b.scrollingElement:b.b",
+    "ody||b.documentElement;b=b.parentWindow||b.defaultView;a=new w(b.pageXO",
+    "ffset||a.scrollLeft,b.pageYOffset||a.scrollTop)}else a=new w(a.scrollLe",
+    "ft,a.scrollTop);return a}var e=kc(a);var f=x(a),h=f.documentElement,m=f",
+    ".body,v=X(h,\"overflow\"),C;for(a=b(a);a;a=b(a)){var t=c(a);if(\"visibl",
+    "e\"!=t.x||\"visible\"!=t.y){var A=fc(a);if(0==A.width||0==A.height)retu",
+    "rn Y;var L=e.right<A.left,T=e.bottom<A.top;if(L&&\"hidden\"==t.x||T&&\"",
+    "hidden\"==t.y)return Y;if(L&&\"visible\"!=t.x||\nT&&\"visible\"!=t.y){L",
+    "=d(a);T=e.bottom<A.top-L.y;if(e.right<A.left-L.x&&\"visible\"!=t.x||T&&",
+    "\"visible\"!=t.x)return Y;e=gc(a);return e==Y?Y:\"scroll\"}L=e.left>=A.",
+    "left+A.width;A=e.top>=A.top+A.height;if(L&&\"hidden\"==t.x||A&&\"hidden",
+    "\"==t.y)return Y;if(L&&\"visible\"!=t.x||A&&\"visible\"!=t.y){if(C&&(t=",
+    "d(a),e.left>=h.scrollWidth-t.x||e.right>=h.scrollHeight-t.y))return Y;e",
+    "=gc(a);return e==Y?Y:\"scroll\"}}}return\"none\"}\nfunction fc(a){var b",
+    "=hc(a);if(b)return b.rect;if(y(a,\"HTML\"))return a=x(a),a=((a?a.parent",
+    "Window||a.defaultView:window)||window).document,a=\"CSS1Compat\"==a.com",
+    "patMode?a.documentElement:a.body,a=new Na(a.clientWidth,a.clientHeight)",
+    ",new W(0,0,a.width,a.height);try{var c=a.getBoundingClientRect()}catch(",
+    "d){return new W(0,0,0,0)}return new W(c.left,c.top,c.right-c.left,c.bot",
+    "tom-c.top)}\nfunction hc(a){var b=y(a,\"MAP\");if(!b&&!y(a,\"AREA\"))re",
+    "turn null;var c=b?a:y(a.parentNode,\"MAP\")?a.parentNode:null,d=null,e=",
+    "null;c&&c.name&&(d=V.ua('/descendant::*[@usemap = \"#'+c.name+'\"]',x(c",
+    ")))&&(e=fc(d),b||\"default\"==a.shape.toLowerCase()||(a=lc(a),b=Math.mi",
+    "n(Math.max(a.left,0),e.width),c=Math.min(Math.max(a.top,0),e.height),e=",
+    "new W(b+e.left,c+e.top,Math.min(a.width,e.width-b),Math.min(a.height,e.",
+    "height-c))));return{da:d,rect:e||new W(0,0,0,0)}}\nfunction lc(a){var b",
+    "=a.shape.toLowerCase();a=a.coords.split(\",\");if(\"rect\"==b&&4==a.len",
+    "gth){var b=a[0],c=a[1];return new W(b,c,a[2]-b,a[3]-c)}if(\"circle\"==b",
+    "&&3==a.length)return b=a[2],new W(a[0]-b,a[1]-b,2*b,2*b);if(\"poly\"==b",
+    "&&2<a.length){for(var b=a[0],c=a[1],d=b,e=c,f=2;f+1<a.length;f+=2)b=Mat",
+    "h.min(b,a[f]),d=Math.max(d,a[f]),c=Math.min(c,a[f+1]),e=Math.max(e,a[f+",
+    "1]);return new W(b,c,d-b,e-c)}return new W(0,0,0,0)}function kc(a){a=fc",
+    "(a);return new ac(a.top,a.left+a.width,a.top+a.height,a.left)}\nfunctio",
+    "n mc(a){return a.replace(/^[^\\S\\xa0]+|[^\\S\\xa0]+$/g,\"\")}\nfunctio",
+    "n nc(a,b,c){if(y(a,\"BR\"))b.push(\"\");else{var d=y(a,\"TD\"),e=X(a,\"",
+    "display\"),f=!d&&!(0<=na(oc,e)),h=k(a.previousElementSibling)?a.previou",
+    "sElementSibling:Qa(a.previousSibling),h=h?X(h,\"display\"):\"\",m=X(a,",
+    "\"float\")||X(a,\"cssFloat\")||X(a,\"styleFloat\");!f||\"run-in\"==h&&",
+    "\"none\"==m||/^[\\s\\xa0]*$/.test(b[b.length-1]||\"\")||b.push(\"\");va",
+    "r v=jc(a),C=null,t=null;v&&(C=X(a,\"white-space\"),t=X(a,\"text-transfo",
+    "rm\"));q(a.childNodes,function(a){c(a,b,v,C,t)});a=b[b.length-1]||\"\";",
+    "!d&&\"table-cell\"!=e||!a||ja(a)||(b[b.length-\n1]+=\" \");f&&\"run-in",
+    "\"!=e&&!/^[\\s\\xa0]*$/.test(a)&&b.push(\"\")}}function pc(a,b){nc(a,b,",
+    "function(a,b,e,f,h){3==a.nodeType&&e?qc(a,b,f,h):y(a)&&pc(a,b)})}var oc",
+    "=\"inline inline-block inline-table none table-cell table-column table-",
+    "column-group\".split(\" \");\nfunction qc(a,b,c,d){a=a.nodeValue.replac",
+    "e(/[\\u200b\\u200e\\u200f]/g,\"\");a=a.replace(/(\\r\\n|\\r|\\n)/g,\"",
+    "\\n\");if(\"normal\"==c||\"nowrap\"==c)a=a.replace(/\\n/g,\" \");a=\"pr",
+    "e\"==c||\"pre-wrap\"==c?a.replace(/[ \\f\\t\\v\\u2028\\u2029]/g,\"\\u00",
+    "a0\"):a.replace(/[\\ \\f\\t\\v\\u2028\\u2029]+/g,\" \");\"capitalize\"=",
+    "=d?a=a.replace(/(^|\\s)(\\S)/g,function(a,b,c){return b+c.toUpperCase()",
+    "}):\"uppercase\"==d?a=a.toUpperCase():\"lowercase\"==d&&(a=a.toLowerCas",
+    "e());c=b.pop()||\"\";ja(c)&&0==a.lastIndexOf(\" \",0)&&(a=a.substr(1));",
+    "b.push(c+a)}\nfunction ic(a){var b=1,c=X(a,\"opacity\");c&&(b=Number(c)",
+    ");(a=cc(a))&&(b*=ic(a));return b}\nfunction rc(a,b,c,d,e){var f;if(3==a",
+    ".nodeType&&c)qc(a,b,d,e);else if(y(a))if(y(a,\"CONTENT\")||y(a,\"SLOT\"",
+    ")){for(f=a;f.parentNode;)f=f.parentNode;f instanceof ShadowRoot?(a=y(a,",
+    "\"CONTENT\")?a.getDistributedNodes():a.assignedNodes(),q(a,function(a){",
+    "rc(a,b,c,d,e)})):sc(a,b)}else if(y(a,\"SHADOW\")){for(f=a;f.parentNode;",
+    ")f=f.parentNode;if(f instanceof ShadowRoot&&(a=f))for(a=a.olderShadowRo",
+    "ot;a;)q(a.childNodes,function(a){rc(a,b,c,d,e)}),a=a.olderShadowRoot}el",
+    "se sc(a,b)}\nfunction sc(a,b){a.shadowRoot&&q(a.shadowRoot.childNodes,f",
+    "unction(a){rc(a,b,!0,null,null)});nc(a,b,function(a,b,e,f,h){var c=null",
+    ";1==a.nodeType?c=a:3==a.nodeType&&(c=a);null!=c&&(null!=c.assignedSlot|",
+    "|c.getDestinationInsertionPoints&&0<c.getDestinationInsertionPoints().l",
+    "ength)||rc(a,b,e,f,h)})};Ma();Ma();function tc(a,b){this.w={};this.g=[]",
+    ";this.F=0;var c=arguments.length;if(1<c){if(c%2)throw Error(\"Uneven nu",
+    "mber of arguments\");for(var d=0;d<c;d+=2)this.set(arguments[d],argumen",
+    "ts[d+1])}else a&&this.addAll(a)}function uc(a){vc(a);return a.g.concat(",
+    ")}g=tc.prototype;g.clear=function(){this.w={};this.F=this.g.length=0};g",
+    ".remove=function(a){return Object.prototype.hasOwnProperty.call(this.w,",
+    "a)?(delete this.w[a],this.F--,this.g.length>2*this.F&&vc(this),!0):!1};",
+    "\nfunction vc(a){var b,c;if(a.F!=a.g.length){for(b=c=0;c<a.g.length;){v",
+    "ar d=a.g[c];Object.prototype.hasOwnProperty.call(a.w,d)&&(a.g[b++]=d);c",
+    "++}a.g.length=b}if(a.F!=a.g.length){var e={};for(b=c=0;c<a.g.length;)d=",
+    "a.g[c],Object.prototype.hasOwnProperty.call(e,d)||(a.g[b++]=d,e[d]=1),c",
+    "++;a.g.length=b}}g.get=function(a,b){return Object.prototype.hasOwnProp",
+    "erty.call(this.w,a)?this.w[a]:b};g.set=function(a,b){Object.prototype.h",
+    "asOwnProperty.call(this.w,a)||(this.F++,this.g.push(a));this.w[a]=b};\n",
+    "g.addAll=function(a){if(a instanceof tc){var b=uc(a);vc(a);for(var c=[]",
+    ",d=0;d<a.g.length;d++)c.push(a.w[a.g[d]]);a=c}else{b=[];var d=0;for(e i",
+    "n a)b[d++]=e;d=[];var e=0;for(c in a)d[e++]=a[c];a=d}for(c=0;c<b.length",
+    ";c++)this.set(b[c],a[c])};g.forEach=function(a,b){for(var c=uc(this),d=",
+    "0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,f,e,this)}};g.clone",
+    "=function(){return new tc(this)};var wc={};function Z(a,b,c){ea(a)&&(a=",
+    "a.b);a=new xc(a);!b||b in wc&&!c||(wc[b]={key:a,shift:!1},c&&(wc[c]={ke",
+    "y:a,shift:!0}));return a}function xc(a){this.code=a}Z(8);Z(9);Z(13);var",
+    " yc=Z(16),zc=Z(17),Ac=Z(18);Z(19);Z(20);Z(27);Z(32,\" \");Z(33);Z(34);Z",
+    "(35);Z(36);Z(37);Z(38);Z(39);Z(40);Z(44);Z(45);Z(46);Z(48,\"0\",\")\");",
+    "Z(49,\"1\",\"!\");Z(50,\"2\",\"@\");Z(51,\"3\",\"#\");Z(52,\"4\",\"$\")",
+    ";Z(53,\"5\",\"%\");Z(54,\"6\",\"^\");Z(55,\"7\",\"&\");Z(56,\"8\",\"*\"",
+    ");Z(57,\"9\",\"(\");Z(65,\"a\",\"A\");Z(66,\"b\",\"B\");Z(67,\"c\",\"C",
+    "\");Z(68,\"d\",\"D\");\nZ(69,\"e\",\"E\");Z(70,\"f\",\"F\");Z(71,\"g\",",
+    "\"G\");Z(72,\"h\",\"H\");Z(73,\"i\",\"I\");Z(74,\"j\",\"J\");Z(75,\"k\"",
+    ",\"K\");Z(76,\"l\",\"L\");Z(77,\"m\",\"M\");Z(78,\"n\",\"N\");Z(79,\"o",
+    "\",\"O\");Z(80,\"p\",\"P\");Z(81,\"q\",\"Q\");Z(82,\"r\",\"R\");Z(83,\"",
+    "s\",\"S\");Z(84,\"t\",\"T\");Z(85,\"u\",\"U\");Z(86,\"v\",\"V\");Z(87,",
+    "\"w\",\"W\");Z(88,\"x\",\"X\");Z(89,\"y\",\"Y\");Z(90,\"z\",\"Z\");var ",
+    "Bc=Z(Ia?{c:91,b:91}:Ha?{c:224,b:91}:{c:0,b:91});Z(Ia?{c:92,b:92}:Ha?{c:",
+    "224,b:93}:{c:0,b:92});Z(Ia?{c:93,b:93}:Ha?{c:0,b:0}:{c:93,b:null});Z({c",
+    ":96,b:96},\"0\");Z({c:97,b:97},\"1\");\nZ({c:98,b:98},\"2\");Z({c:99,b:",
+    "99},\"3\");Z({c:100,b:100},\"4\");Z({c:101,b:101},\"5\");Z({c:102,b:102",
+    "},\"6\");Z({c:103,b:103},\"7\");Z({c:104,b:104},\"8\");Z({c:105,b:105},",
+    "\"9\");Z({c:106,b:106},\"*\");Z({c:107,b:107},\"+\");Z({c:109,b:109},\"",
+    "-\");Z({c:110,b:110},\".\");Z({c:111,b:111},\"/\");Z(144);Z(112);Z(113)",
+    ";Z(114);Z(115);Z(116);Z(117);Z(118);Z(119);Z(120);Z(121);Z(122);Z(123);",
+    "Z({c:107,b:187},\"=\",\"+\");Z(108,\",\");Z({c:109,b:189},\"-\",\"_\");",
+    "Z(188,\",\",\"<\");Z(190,\".\",\">\");Z(191,\"/\",\"?\");Z(192,\"`\",\"",
+    "~\");Z(219,\"[\",\"{\");\nZ(220,\"\\\\\",\"|\");Z(221,\"]\",\"}\");Z({c",
+    ":59,b:186},\";\",\":\");Z(222,\"'\",'\"');var Cc=new tc;Cc.set(1,yc);Cc",
+    ".set(2,zc);Cc.set(4,Ac);Cc.set(8,Bc);(function(a){var b=new tc;q(uc(a),",
+    "function(c){b.set(a.get(c).code,c)});return b})(Cc);ba(\"_\",function(a",
+    "){var b=[];bc?sc(a,b):pc(a,b);var c=b;a=c.length;for(var b=Array(a),c=l",
+    "(c)?c.split(\"\"):c,d=0;d<a;d++)d in c&&(b[d]=mc.call(void 0,c[d]));ret",
+    "urn mc(b.join(\"\\n\")).replace(/\\xa0/g,\" \")});; return this._.apply",
+    "(null,arguments);}.apply({navigator:typeof window!='undefined'?window.n",
+    "avigator:null,document:typeof window!='undefined'?window.document:null}",
+    ", arguments);}",
     NULL
 };
 
diff --git a/third_party/webdriver/patch.diff b/third_party/webdriver/patch.diff
index 0a70c275..657f6253 100644
--- a/third_party/webdriver/patch.diff
+++ b/third_party/webdriver/patch.diff
@@ -1,24 +1,33 @@
 diff --git a/javascript/atoms/dom.js b/javascript/atoms/dom.js
-index f0a3b84da5..c7a1b05054 100644
+index 78b78e1038..f1d0b424b0 100644
 --- a/javascript/atoms/dom.js
 +++ b/javascript/atoms/dom.js
-@@ -561,14 +561,8 @@ bot.dom.isShown = function(elem, opt_ignoreOpacity) {
-       do {
-         parent = bot.dom.getParentNodeInComposedDom(e);
-         if (parent instanceof ShadowRoot) {
--          if (parent.host.shadowRoot != parent) {
--            // There is a younger shadow root, which will take precedence over
--            // the shadow this element is in, thus this element won't be
--            // displayed.
--            return false;
--          } else {
--            parent = parent.host;
--          }
-+          // For backward compatibility, treat all shadow roots as shown.
-+          return true;
-         } else if (parent && (parent.nodeType == goog.dom.NodeType.DOCUMENT ||
-             parent.nodeType == goog.dom.NodeType.DOCUMENT_FRAGMENT)) {
-           parent = null;
+@@ -587,14 +587,8 @@ bot.dom.isShown = function(elem, opt_ignoreOpacity) {
+     var parent = bot.dom.getParentNodeInComposedDom(e);
+ 
+     if (bot.dom.IS_SHADOW_DOM_ENABLED && (parent instanceof ShadowRoot)) {
+-      if (parent.host.shadowRoot !== parent) {
+-        // There is a younger shadow root, which will take precedence over
+-        // the shadow this element is in, thus this element won't be
+-        // displayed.
+-        return false;
+-      } else {
+-        parent = parent.host;
+-      }
++      // For backward compatibility, treat all shadow roots as shown.
++      return true;
+     }
+ 
+     if (parent && (parent.nodeType == goog.dom.NodeType.DOCUMENT ||
+@@ -602,7 +596,7 @@ bot.dom.isShown = function(elem, opt_ignoreOpacity) {
+       return true;
+     }
+ 
+-    return parent && displayed(parent);
++    return !!parent && displayed(parent);
+   }
+ 
+   return bot.dom.isShown_(elem, !!opt_ignoreOpacity, displayed);
 diff --git a/javascript/atoms/mouse.js b/javascript/atoms/mouse.js
 index 737ed50f62..1bc9e858f5 100644
 --- a/javascript/atoms/mouse.js
@@ -44,24 +53,22 @@
      buttonValueMap[bot.events.EventType.CLICK] = [0, 1, 2, null];
      buttonValueMap[bot.events.EventType.CONTEXTMENU] = [null, null, 2, null];
 diff --git a/javascript/chrome-driver/atoms.js b/javascript/chrome-driver/atoms.js
-index 5cf4416460..b21fea617c 100644
+index 5cf4416460..329390cf1f 100644
 --- a/javascript/chrome-driver/atoms.js
 +++ b/javascript/chrome-driver/atoms.js
-@@ -142,6 +142,12 @@ webdriver.chrome.scrollIntoView_ = function(elem, region, center) {
+@@ -142,6 +142,10 @@ webdriver.chrome.scrollIntoView_ = function(elem, region, center) {
  
    offset = goog.style.getClientPosition(elem);
    var windowSize = goog.dom.getDomHelper(elem).getViewportSize();
-+  // Chrome 61.0.3138 and above uses doc.documentElement, while older
-+  // Chrome uses doc.body. We can't reliably detect Chrome version because
-+  // userAgent string can be overridden, so just call scrollHelper on both.
-+  // TBD(johnchen@chromium.org): Remove doc.body when we stop supporting
-+  // Chrome 61.0.3137.
++  // Chrome uses either doc.documentElement or doc.body, depending on
++  // compatibility settings. For reliability, call scrollHelper on both.
++  // Calling scrollHelper on the wrong object is harmless.
 +  scrollHelper(doc.documentElement, windowSize, offset, region, center);
    scrollHelper(doc.body, windowSize, offset, region, center);
  };
  
 diff --git a/rake-tasks/crazy_fun/mappings/javascript.rb b/rake-tasks/crazy_fun/mappings/javascript.rb
-index 982d36314e..ae0c3e460b 100644
+index 1ac2b2066a..dfa11fbbc2 100644
 --- a/rake-tasks/crazy_fun/mappings/javascript.rb
 +++ b/rake-tasks/crazy_fun/mappings/javascript.rb
 @@ -857,6 +857,8 @@ module Javascript
diff --git a/third_party/yasm/BUILD.gn b/third_party/yasm/BUILD.gn
index b261e4d8..35a85b1 100644
--- a/third_party/yasm/BUILD.gn
+++ b/third_party/yasm/BUILD.gn
@@ -41,7 +41,11 @@
 
     # Don't define _DEBUG. Modest savings, but good for consistency.
     "//build/config:debug",
+
+    # Don't enable sanitizers for build tools. They slow down the overall build.
+    "//build/config/sanitizers:default_sanitizer_flags",
   ]
+
   configs_to_add += [
     "//build/config:release",
     "//build/config/compiler:optimize_max",
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a9c58de1..b7fb90d 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -3209,6 +3209,7 @@
   <int value="5" label="Service Worker unavailable"/>
   <int value="6" label="Quota exceeded"/>
   <int value="7" label="Permission denied"/>
+  <int value="8" label="Registration Limit Exceeded"/>
 </enum>
 
 <enum name="BackgroundFetchEventDispatchResult">
@@ -29124,6 +29125,7 @@
   <int value="-979057409" label="enable-seccomp-filter-sandbox"/>
   <int value="-979034258" label="disable-ntp-other-sessions-menu"/>
   <int value="-978700508" label="disable-simplified-fullscreen-ui"/>
+  <int value="-977770313" label="AndroidSurfaceControl:enabled"/>
   <int value="-977476498" label="disable-eol-notification"/>
   <int value="-974378602" label="WebAuthenticationCable:disabled"/>
   <int value="-973509424" label="NewTabPageIcons:disabled"/>
@@ -29626,6 +29628,7 @@
       label="AutofillSaveCardDialogUnlabeledExpirationDate:enabled"/>
   <int value="37024318" label="disable-affiliation-based-matching"/>
   <int value="37045987" label="AutofillPreviewStyleExperiment:disabled"/>
+  <int value="42844603" label="AndroidSurfaceControl:disabled"/>
   <int value="44088203" label="ExpensiveBackgroundTimerThrottling:enabled"/>
   <int value="48159177" label="reduced-referrer-granularity"/>
   <int value="48223610" label="SiteSettings:disabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0120bc0..bda6b0d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -72294,6 +72294,15 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.AbleToSavePasswordsOnSuccessfulLogin"
+    enum="BooleanSuccess">
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    Records attempts to prompt user to save a password when password store is
+    not ready for saving passwords. Recorded once per form submission.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.AboutBlankPasswordSubmission"
     enum="BooleanMainFrame">
   <owner>alexmos@chromium.org</owner>
@@ -73324,6 +73333,14 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.PasswordStoreInitResult" enum="BooleanSuccess">
+  <owner>vasilii@chromium.org</owner>
+  <summary>
+    Success rate of initialization of password store. Recorded for every user
+    once on the Chrome profile startup.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.PasswordSyncState" enum="PasswordSyncState">
   <owner>gcasto@chromium.org</owner>
   <owner>rouslan@chromium.org</owner>
@@ -130930,6 +130947,7 @@
   <suffix name="ChromeFilenameClientIncident" label="(Obsolete, not recorded)"/>
   <suffix name="ChromeUrlClientIncident"/>
   <suffix name="IpMalware"/>
+  <suffix name="UrlBilling"/>
   <suffix name="UrlCsdDownloadWhitelist"/>
   <suffix name="UrlCsdWhitelist"/>
   <suffix name="UrlMalBin"/>
diff --git a/tools/perf/contrib/vr_benchmarks/vr_sample_page.py b/tools/perf/contrib/vr_benchmarks/vr_sample_page.py
index 6f815ab..2aa3db1 100644
--- a/tools/perf/contrib/vr_benchmarks/vr_sample_page.py
+++ b/tools/perf/contrib/vr_benchmarks/vr_sample_page.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import os
+import re
 from telemetry import page
 from contrib.vr_benchmarks import (shared_android_vr_page_state as
                                    vr_state)
@@ -26,6 +27,13 @@
     if url_parameters is not None:
       url += '?' + '&'.join(url_parameters)
     name = url.replace('.html', '')
+    # Replace characters that are unsupported by the perf dashboard here so that
+    # the name reported on the dashboard can be used as a story filter.
+    # We don't use a the \W+ regex like other benchmarks because we need to
+    # keep certain non-alphanumeric characters around for backwards naming
+    # compatibility. This regex should replace anything except alphanumeric,
+    # question mark, dash, and period characters with underscores.
+    name = re.sub(r'[^a-zA-Z\d\?\-\.]+', '_', name)
     url = 'file://' + os.path.join(sample_directory, url)
     super(_VrXrSamplePage, self).__init__(
         url=url,
diff --git a/ui/accessibility/platform/aura_window_properties.cc b/ui/accessibility/platform/aura_window_properties.cc
index 812b4c9..2a51fad 100644
--- a/ui/accessibility/platform/aura_window_properties.cc
+++ b/ui/accessibility/platform/aura_window_properties.cc
@@ -9,11 +9,9 @@
 
 DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AX_EXPORT, ax::mojom::Role)
 
-DEFINE_EXPORTED_UI_CLASS_PROPERTY_TYPE(AX_EXPORT, ui::AXTreeID*)
-
 namespace ui {
 
-DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(ui::AXTreeID, kChildAXTreeID, nullptr);
+DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(std::string, kChildAXTreeID, nullptr);
 
 DEFINE_UI_CLASS_PROPERTY_KEY(ax::mojom::Role,
                              kAXRoleOverride,
diff --git a/ui/accessibility/platform/aura_window_properties.h b/ui/accessibility/platform/aura_window_properties.h
index e4e89c7e..8fcf89f 100644
--- a/ui/accessibility/platform/aura_window_properties.h
+++ b/ui/accessibility/platform/aura_window_properties.h
@@ -5,15 +5,19 @@
 #ifndef UI_ACCESSIBILITY_PLATFORM_AURA_WINDOW_PROPERTIES_H_
 #define UI_ACCESSIBILITY_PLATFORM_AURA_WINDOW_PROPERTIES_H_
 
+#include <string>
+
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_export.h"
-#include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/aura/window.h"
 
 namespace ui {
 
-AX_EXPORT extern const aura::WindowProperty<ui::AXTreeID*>* const
-    kChildAXTreeID;
+// Value is a serialized |ui::AXTreeID| because code in //ui/aura/mus needs
+// to serialize the window property, but //ui/aura cannot depend on
+// //ui/accessibility and hence cannot know about the type ui::AXTreeID.
+// TODO(dmazzoni): Convert from string to base::UnguessableToken.
+AX_EXPORT extern const aura::WindowProperty<std::string*>* const kChildAXTreeID;
 
 AX_EXPORT extern const aura::WindowProperty<ax::mojom::Role>* const
     kAXRoleOverride;
diff --git a/ui/aura/test/ui_controls_factory_ozone.cc b/ui/aura/test/ui_controls_factory_ozone.cc
index c4bcb4c3..22911107 100644
--- a/ui/aura/test/ui_controls_factory_ozone.cc
+++ b/ui/aura/test/ui_controls_factory_ozone.cc
@@ -6,6 +6,7 @@
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/optional.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "services/service_manager/public/cpp/connector.h"
@@ -135,6 +136,7 @@
 
     gfx::Point host_location = display_location;
     host_->ConvertDIPToPixels(&host_location);
+    last_mouse_location_ = host_location;
 
     ui::EventType event_type;
 
@@ -158,18 +160,24 @@
                                      int button_state,
                                      base::OnceClosure closure,
                                      int accelerator_state) override {
-    // The location needs to be in display's coordinate.
-    gfx::Point display_location = host_->window()->env()->last_mouse_location();
-    display::Display display;
-    if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(
-            host_->GetDisplayId(), &display)) {
-      LOG(ERROR) << "Failed to see the display for " << host_->GetDisplayId();
-      return false;
-    }
-    display_location -= display.bounds().OffsetFromOrigin();
+    gfx::Point host_location;
+    if (last_mouse_location_.has_value()) {
+      host_location = last_mouse_location_.value();
+    } else {
+      // The location needs to be in display's coordinate.
+      gfx::Point display_location =
+          host_->window()->env()->last_mouse_location();
+      display::Display display;
+      if (!display::Screen::GetScreen()->GetDisplayWithDisplayId(
+              host_->GetDisplayId(), &display)) {
+        LOG(ERROR) << "Failed to see the display for " << host_->GetDisplayId();
+        return false;
+      }
+      display_location -= display.bounds().OffsetFromOrigin();
 
-    gfx::Point host_location = display_location;
-    host_->ConvertDIPToPixels(&host_location);
+      host_location = display_location;
+      host_->ConvertDIPToPixels(&host_location);
+    }
 
     int changed_button_flag = 0;
 
@@ -316,6 +324,11 @@
   WindowTreeHost* host_;
   ws::mojom::EventInjectorPtr event_injector_;
 
+  // The mouse location for the last SendMouseEventsNotifyWhenDone call. This is
+  // used rather than Env::last_mouse_location() as Env::last_mouse_location()
+  // is updated asynchronously with mus.
+  base::Optional<gfx::Point> last_mouse_location_;
+
   // Mask of the mouse buttons currently down. This is static as it needs to
   // track the state globally for all displays. A UIControlsOzone instance is
   // created for each display host.
diff --git a/ui/base/mojo/clipboard_host.h b/ui/base/mojo/clipboard_host.h
index bab35e0..b36e591 100644
--- a/ui/base/mojo/clipboard_host.h
+++ b/ui/base/mojo/clipboard_host.h
@@ -58,7 +58,7 @@
   void WriteBitmap(const SkBitmap& bitmap) override;
   void WriteData(const std::string& type, const std::string& data) override;
   void CommitWrite(ClipboardType type) override;
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) && !defined(OS_IOS)
   void WriteStringToFindPboard(const base::string16& text) override;
 #endif
 
diff --git a/ui/file_manager/file_manager/foreground/js/crostini.js b/ui/file_manager/file_manager/foreground/js/crostini.js
index 7f20ea1..ec49d543 100644
--- a/ui/file_manager/file_manager/foreground/js/crostini.js
+++ b/ui/file_manager/file_manager/foreground/js/crostini.js
@@ -5,6 +5,12 @@
 const Crostini = {};
 
 /**
+ * Set from cmd line flag 'crostini-files'.
+ * @type {boolean}
+ */
+Crostini.IS_CROSTINI_FILES_ENABLED = false;
+
+/**
  * Maintains a list of paths shared with the crostini container.
  * Keyed by VolumeManagerCommon.RootType, with boolean set values
  * of string paths.  e.g. {'Downloads': {'/foo': true, '/bar': true}}.
@@ -75,3 +81,16 @@
   return volumeManager.getLocationInfo(entry).rootType ===
       VolumeManagerCommon.RootType.CROSTINI;
 };
+
+/**
+ * Returns true if entry can be shared with Crostini.
+ * @param {!Entry} entry
+ * @param {!VolumeManager} volumeManager
+ */
+Crostini.canSharePath = function(entry, volumeManager) {
+  // Do not allow root, or non-directories in root.
+  return Crostini.IS_CROSTINI_FILES_ENABLED && entry.fullPath !== '/' &&
+      (entry.isDirectory || entry.fullPath.split('/').length > 2) &&
+      volumeManager.getLocationInfo(entry).rootType ===
+      VolumeManagerCommon.RootType.DOWNLOADS;
+};
diff --git a/ui/file_manager/file_manager/foreground/js/crostini_unittest.html b/ui/file_manager/file_manager/foreground/js/crostini_unittest.html
index 7fe283a..f494b7e 100644
--- a/ui/file_manager/file_manager/foreground/js/crostini_unittest.html
+++ b/ui/file_manager/file_manager/foreground/js/crostini_unittest.html
@@ -5,6 +5,7 @@
   -->
 
 <script src="../../common/js/mock_entry.js"></script>
+<script src="../../common/js/volume_manager_common.js"></script>
 
 <script src="crostini.js"></script>
 <script src="crostini_unittest.js"></script>
diff --git a/ui/file_manager/file_manager/foreground/js/crostini_unittest.js b/ui/file_manager/file_manager/foreground/js/crostini_unittest.js
index 46ebe8e..6d8d893b1 100644
--- a/ui/file_manager/file_manager/foreground/js/crostini_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/crostini_unittest.js
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-const volumeManager = {
+const volumeManagerTest = {
   getLocationInfo: (entry) => {
-    return {root: 'testroot'};
+    return {rootType: 'testroot'};
   },
 };
 
@@ -16,17 +16,46 @@
   const foo2 = new MockDirectoryEntry(mockFileSystem, '/foo2');
   const foobar2 = new MockDirectoryEntry(mockFileSystem, '/foo2/bar2');
 
-  assertFalse(Crostini.isPathShared(foo1, volumeManager));
+  assertFalse(Crostini.isPathShared(foo1, volumeManagerTest));
 
-  Crostini.registerSharedPath(foo1, volumeManager);
-  assertFalse(Crostini.isPathShared(root, volumeManager));
-  assertTrue(Crostini.isPathShared(foo1, volumeManager));
-  assertTrue(Crostini.isPathShared(foobar1, volumeManager));
+  Crostini.registerSharedPath(foo1, volumeManagerTest);
+  assertFalse(Crostini.isPathShared(root, volumeManagerTest));
+  assertTrue(Crostini.isPathShared(foo1, volumeManagerTest));
+  assertTrue(Crostini.isPathShared(foobar1, volumeManagerTest));
 
-  Crostini.registerSharedPath(foobar2, volumeManager);
-  assertFalse(Crostini.isPathShared(foo2, volumeManager));
-  assertTrue(Crostini.isPathShared(foobar2, volumeManager));
+  Crostini.registerSharedPath(foobar2, volumeManagerTest);
+  assertFalse(Crostini.isPathShared(foo2, volumeManagerTest));
+  assertTrue(Crostini.isPathShared(foobar2, volumeManagerTest));
 
-  Crostini.unregisterSharedPath(foobar2, volumeManager);
-  assertFalse(Crostini.isPathShared(foobar2, volumeManager));
+  Crostini.unregisterSharedPath(foobar2, volumeManagerTest);
+  assertFalse(Crostini.isPathShared(foobar2, volumeManagerTest));
+}
+
+const volumeManagerDownloads = {
+  getLocationInfo: (entry) => {
+    return {rootType: 'downloads'};
+  },
+};
+
+function testCanSharePath() {
+  Crostini.IS_CROSTINI_FILES_ENABLED = true;
+
+  const mockFileSystem = new MockFileSystem('volumeId');
+  const root = new MockDirectoryEntry(mockFileSystem, '/');
+  const rootFile = new MockEntry(mockFileSystem, '/file');
+  const rootFolder = new MockDirectoryEntry(mockFileSystem, '/folder');
+  const fooFile = new MockEntry(mockFileSystem, '/foo/folder');
+  const fooFolder = new MockDirectoryEntry(mockFileSystem, '/foo/folder');
+
+  assertFalse(Crostini.canSharePath(root, volumeManagerTest));
+  assertFalse(Crostini.canSharePath(rootFile, volumeManagerTest));
+  assertFalse(Crostini.canSharePath(rootFolder, volumeManagerTest));
+  assertFalse(Crostini.canSharePath(fooFile, volumeManagerTest));
+  assertFalse(Crostini.canSharePath(fooFolder, volumeManagerTest));
+
+  assertFalse(Crostini.canSharePath(root, volumeManagerDownloads));
+  assertFalse(Crostini.canSharePath(rootFile, volumeManagerDownloads));
+  assertTrue(Crostini.canSharePath(rootFolder, volumeManagerDownloads));
+  assertTrue(Crostini.canSharePath(fooFile, volumeManagerDownloads));
+  assertTrue(Crostini.canSharePath(fooFolder, volumeManagerDownloads));
 }
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index a4e36da..db0993ff 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -1222,6 +1222,12 @@
    */
   FileManager.prototype.setupCrostini_ = function() {
     chrome.fileManagerPrivate.isCrostiniEnabled((enabled) => {
+      // Check for 'crostini-files' cmd line flag.
+      chrome.commandLinePrivate.hasSwitch('crostini-files', (filesEnabled) => {
+        Crostini.IS_CROSTINI_FILES_ENABLED = filesEnabled;
+      });
+
+      // Setup Linux files fake root.
       this.directoryTree.dataModel.linuxFilesItem = enabled ?
           new NavigationModelFakeItem(
               str('LINUX_FILES_ROOT_LABEL'), NavigationModelItemType.CROSTINI,
@@ -1229,6 +1235,7 @@
                   str('LINUX_FILES_ROOT_LABEL'),
                   VolumeManagerCommon.RootType.CROSTINI, true)) :
           null;
+
       // Redraw the tree even if not enabled.  This is required for testing.
       this.directoryTree.redraw(false);
 
@@ -1241,7 +1248,6 @@
           Crostini.registerSharedPath(entries[i], assert(this.volumeManager_));
         }
       });
-
     });
   };
 
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 6eb8adc..5e1700b 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -356,13 +356,6 @@
       'disable-zip-archiver-packer', function(disabled) {
         CommandHandler.IS_ZIP_ARCHIVER_PACKER_ENABLED_ = !disabled;
       });
-  chrome.fileManagerPrivate.isCrostiniEnabled((enabled) => {
-    if (enabled) {
-      chrome.commandLinePrivate.hasSwitch('crostini-files', (enabled) => {
-        CommandHandler.IS_CROSTINI_FILES_ENABLED_ = enabled;
-      });
-    }
-  });
 };
 
 /**
@@ -373,13 +366,6 @@
 CommandHandler.IS_ZIP_ARCHIVER_PACKER_ENABLED_ = false;
 
 /**
- * A flag that determines whether crostini file sharing is enabled.
- * @type {boolean}
- * @private
- */
-CommandHandler.IS_CROSTINI_FILES_ENABLED_ = false;
-
-/**
  * Supported disk file system types for renaming.
  * @type {!Array<!VolumeManagerCommon.FileSystemType>}
  * @const
@@ -1676,12 +1662,9 @@
   canExecute: function(event, fileManager) {
     // Must be single directory subfolder of Downloads not already shared.
     const entries = CommandUtil.getCommandEntries(event.target);
-    event.canExecute = CommandHandler.IS_CROSTINI_FILES_ENABLED_ &&
-        entries.length === 1 && entries[0].isDirectory &&
-        !Crostini.isPathShared(entries[0], assert(fileManager.volumeManager)) &&
-        entries[0].fullPath !== '/' &&
-        fileManager.volumeManager.getLocationInfo(entries[0]).rootType ===
-            VolumeManagerCommon.RootType.DOWNLOADS;
+    event.canExecute = entries.length === 1 && entries[0].isDirectory &&
+        !Crostini.isPathShared(entries[0], fileManager.volumeManager) &&
+        Crostini.canSharePath(entries[0], fileManager.volumeManager);
     event.command.setHidden(!event.canExecute);
   }
 });
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks.js b/ui/file_manager/file_manager/foreground/js/file_tasks.js
index 7195a2fb..905d280 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks.js
@@ -440,24 +440,6 @@
 };
 
 /**
- * @param {string} taskId Task identifier.
- * @return {boolean} True if the task ID is for crostini.
- * @private
- */
-FileTasks.isCrostiniTask_ = function(taskId) {
-  return taskId.split('|', 2)[1] === 'crostini';
-};
-
-/**
- * @return {boolean} True if all entries are crostini.
- * @private
- */
-FileTasks.prototype.allCrostiniEntries_ = function() {
-  return this.entries_.every(
-      entry => Crostini.isCrostiniEntry(entry, this.volumeManager_));
-};
-
-/**
  * Annotates tasks returned from the API.
  *
  * @param {!Array<!chrome.fileManagerPrivate.FileTask>} tasks Input tasks from
@@ -565,6 +547,102 @@
 };
 
 /**
+ * Checks if task is a crostini task and all entries are accessible to crostini.
+ * If entries can be shared with crostini, share dialog is shown.  Otherwise if
+ * entries cannot be shared, the Unable to Open dialog is shown.
+ * @param {!chrome.fileManagerPrivate.FileTask} task Task to run.
+ * @return {boolean} True if crostini task and dialog is shown.
+ * @private
+ */
+FileTasks.prototype.maybeShowCrostiniShareDialog_ = function(task) {
+  // Check if this is a crostini task.
+  if (task.taskId.split('|', 2)[1] !== 'crostini' || this.entries_.length < 1)
+    return false;
+
+  let showUnableToOpen = false;
+  let showShareBeforeOpen = false;
+  let notSharedCount = 0;
+  let firstEntryNotShared;
+  for (let i = 0; i < this.entries_.length; i++) {
+    const entry = this.entries_[i];
+    if (Crostini.isCrostiniEntry(entry, this.volumeManager_) ||
+        Crostini.isPathShared(entry, this.volumeManager_)) {
+      continue;
+    }
+    if (!Crostini.canSharePath(entry, this.volumeManager_)) {
+      showUnableToOpen = true;
+      break;
+    }
+    notSharedCount++;
+    // Share before open.  Ensure all entries are in the same directory.
+    showShareBeforeOpen = true;
+    if (!firstEntryNotShared) {
+      firstEntryNotShared = entry;
+    } else if (!util.isSiblingEntry(entry, firstEntryNotShared)) {
+      showUnableToOpen = true;
+      break;
+    }
+  }
+
+  // Show unable to open alert dialog.
+  if (showUnableToOpen) {
+    this.ui_.alertDialog.showHtml(
+        strf('UNABLE_TO_OPEN_CROSTINI_TITLE', task.title),
+        strf('UNABLE_TO_OPEN_CROSTINI', task.title));
+    return true;
+  }
+
+  // Show share before open confirm dialog.
+  if (showShareBeforeOpen) {
+    const parts = firstEntryNotShared.fullPath.split('/');
+    const parentName = parts[parts.length - 2];
+    this.ui_.confirmDialog.showHtml(
+        strf('SHARE_BEFORE_OPEN_CROSTINI_TITLE', task.title),
+        notSharedCount > 1 ?
+            strf('SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE', notSharedCount) :
+            strf(
+                'SHARE_BEFORE_OPEN_CROSTINI_SINGLE',
+                `<b>${firstEntryNotShared.name}</b>`),
+        this.sharePathWithCrostiniAndExecute_.bind(this, task), () => {});
+    return true;
+  }
+
+  // No dialogs.
+  return false;
+};
+
+/**
+ * Share paths from entries and execute task.
+ * @param {!chrome.fileManagerPrivate.FileTask} task Task to run.
+ */
+FileTasks.prototype.sharePathWithCrostiniAndExecute_ = function(task) {
+  const entry = this.entries_[0];
+  entry.getParent(
+      (/** @type {!DirectoryEntry} */ dir) => {
+        chrome.fileManagerPrivate.sharePathWithCrostini(dir, () => {
+          if (chrome.runtime.lastError) {
+            console.error(
+                'Error sharing with linux to execute: ' +
+                chrome.runtime.lastError.message);
+          } else {
+            // Register path as shared, and execute. This will be the 2nd
+            // time we have gone through executeInternal_().  The first time,
+            // we showed the share dialog, and did not execute, now we
+            // should detect that paths are already shared, and it is OK to
+            // execute.
+            Crostini.registerSharedPath(dir, this.volumeManager_);
+            this.executeInternal_(task);
+          }
+        });
+      },
+      (fileError) => {
+        console.error(
+            'Error getting parent for ' + entry.fullPath + '.  ' +
+            util.getFileErrorString(fileError.name));
+      });
+};
+
+/**
  * Executes default task.
  *
  * @param {function(boolean, Array<!Entry>)=} opt_callback Called when the
@@ -723,11 +801,8 @@
     this.taskHistory_.recordTaskExecuted(task.taskId);
     if (FileTasks.isInternalTask_(task.taskId)) {
       this.executeInternalTask_(task.taskId);
-    } else if (
-        FileTasks.isCrostiniTask_(task.taskId) && !this.allCrostiniEntries_()) {
-      this.ui_.alertDialog.showHtml(
-          strf('UNABLE_TO_OPEN_CROSTINI_TITLE', task.title),
-          strf('UNABLE_TO_OPEN_CROSTINI', task.title));
+    } else if (this.maybeShowCrostiniShareDialog_(task)) {
+      // Nothing to do, dialog will be shown.
     } else {
       FileTasks.recordZipHandlerUMA_(task.taskId);
       chrome.fileManagerPrivate.executeTask(
diff --git a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
index 9286c58..d1f0b1bfe 100644
--- a/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
+++ b/ui/file_manager/file_manager/foreground/js/file_tasks_unittest.js
@@ -14,6 +14,7 @@
 };
 
 loadTimeData.data = {
+  MORE_ACTIONS_BUTTON_LABEL: 'MORE_ACTIONS_BUTTON_LABEL',
   NO_TASK_FOR_EXECUTABLE: 'NO_TASK_FOR_EXECUTABLE',
   NO_TASK_FOR_FILE_URL: 'NO_TASK_FOR_FILE_URL',
   NO_TASK_FOR_FILE: 'NO_TASK_FOR_FILE',
@@ -21,9 +22,13 @@
   NO_TASK_FOR_CRX: 'NO_TASK_FOR_CRX',
   NO_TASK_FOR_CRX_TITLE: 'NO_TASK_FOR_CRX_TITLE',
   OPEN_WITH_BUTTON_LABEL: 'OPEN_WITH_BUTTON_LABEL',
+  SHARE_BEFORE_OPEN_CROSTINI_TITLE: 'SHARE_BEFORE_OPEN_CROSTINI_TITLE',
+  SHARE_BEFORE_OPEN_CROSTINI_SINGLE: 'SHARE_BEFORE_OPEN_CROSTINI_SINGLE',
+  SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE: 'SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE',
   TASK_INSTALL_LINUX_PACKAGE: 'TASK_INSTALL_LINUX_PACKAGE',
   TASK_OPEN: 'TASK_OPEN',
-  MORE_ACTIONS_BUTTON_LABEL: 'MORE_ACTIONS_BUTTON_LABEL'
+  UNABLE_TO_OPEN_CROSTINI_TITLE: 'UNABLE_TO_OPEN_CROSTINI_TITLE',
+  UNABLE_TO_OPEN_CROSTINI: 'UNABLE_TO_OPEN_CROSTINI',
 };
 
 function setUp() {
@@ -474,3 +479,93 @@
   });
   reportPromise(promise, callback);
 }
+
+function testMaybeShowCrostiniShareDialog() {
+  const volumeManagerDownloads = {
+    getLocationInfo: (entry) => {
+      return {rootType: 'downloads'};
+    }
+  };
+  const mockFileSystem = new MockFileSystem('downloads');
+  const sharedDir = new MockDirectoryEntry(mockFileSystem, '/shared');
+  const shared = new MockFileEntry(mockFileSystem, '/shared/file');
+  Crostini.registerSharedPath(sharedDir, volumeManagerDownloads);
+  const notShared1 = new MockFileEntry(mockFileSystem, '/notShared/file1');
+  const notShared2 = new MockFileEntry(mockFileSystem, '/notShared/file2');
+  const otherNotShared =
+      new MockFileEntry(mockFileSystem, '/otherNotShared/file');
+
+  const expect =
+      (comment, entries, expectShareDialogShown, expectedTitle,
+       expectedMessage) => {
+        let showHtmlCalled = false;
+        const showHtml = (title, message) => {
+          showHtmlCalled = true;
+          assertEquals(
+              expectedTitle, title, 'crostini share dialog title: ' + comment);
+          assertEquals(
+              expectedMessage, message,
+              'crostini share dialog message: ' + comment);
+        };
+        const fakeFilesTask = {
+          entries_: entries,
+          ui_: {
+            alertDialog: {showHtml: showHtml},
+            confirmDialog: {showHtml: showHtml},
+          },
+          sharePathWithCrostiniAndExecute_: () => {},
+          volumeManager_: volumeManagerDownloads,
+        };
+        const crostiniTask = {taskId: '|crostini|'};
+        const shareDialogShown =
+            FileTasks.prototype.maybeShowCrostiniShareDialog_.call(
+                fakeFilesTask, crostiniTask);
+        assertEquals(
+            expectShareDialogShown, shareDialogShown,
+            'dialog shown: ' + comment);
+        assertEquals(
+            expectShareDialogShown, showHtmlCalled,
+            'showHtml called:' + comment);
+      };
+
+
+  expect('No entries', [], false, '', '');
+
+  Crostini.IS_CROSTINI_FILES_ENABLED = false;
+  expect(
+      'Single entry, crostini-files not enabled', [notShared1], true,
+      'UNABLE_TO_OPEN_CROSTINI_TITLE', 'UNABLE_TO_OPEN_CROSTINI');
+
+  Crostini.IS_CROSTINI_FILES_ENABLED = true;
+
+  expect(
+      'Single entry, not shared', [notShared1], true,
+      'SHARE_BEFORE_OPEN_CROSTINI_TITLE', 'SHARE_BEFORE_OPEN_CROSTINI_SINGLE');
+
+  expect('Single entry, shared', [shared], false, '', '');
+
+  expect(
+      '2 entries, not shared, same dir', [notShared1, notShared2], true,
+      'SHARE_BEFORE_OPEN_CROSTINI_TITLE',
+      'SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE');
+
+  expect(
+      '2 entries, not shared, different dir', [notShared1, otherNotShared],
+      true, 'UNABLE_TO_OPEN_CROSTINI_TITLE', 'UNABLE_TO_OPEN_CROSTINI');
+
+  expect(
+      '2 entries, 1 not shared, different dir, not shared first',
+      [notShared1, shared], true, 'SHARE_BEFORE_OPEN_CROSTINI_TITLE',
+      'SHARE_BEFORE_OPEN_CROSTINI_SINGLE');
+
+  expect(
+      '2 entries, 1 not shared, different dir, shared first',
+      [shared, notShared1], true, 'SHARE_BEFORE_OPEN_CROSTINI_TITLE',
+      'SHARE_BEFORE_OPEN_CROSTINI_SINGLE');
+
+  expect(
+      '3 entries, 2 not shared, different dir',
+      [shared, notShared1, notShared2], true,
+      'SHARE_BEFORE_OPEN_CROSTINI_TITLE',
+      'SHARE_BEFORE_OPEN_CROSTINI_MULTIPLE');
+}
diff --git a/ui/file_manager/file_manager/test/BUILD.gn b/ui/file_manager/file_manager/test/BUILD.gn
index 1d589f3..7c5254a8c 100644
--- a/ui/file_manager/file_manager/test/BUILD.gn
+++ b/ui/file_manager/file_manager/test/BUILD.gn
@@ -8,7 +8,6 @@
   script = "//ui/file_manager/file_manager/test/scripts/create_test_main.py"
   output = "$target_gen_dir/../test.html"
   sources = [
-    "../../../webui/resources/css/text_defaults.css",
     "../background/js/background_common_scripts.js",
     "../background/js/background_scripts.js",
     "../foreground/elements/elements_bundle.html",
@@ -18,6 +17,9 @@
     "../foreground/js/elements_importer.js",
     "../foreground/js/main_scripts.js",
     "../main.html",
+    "//chrome/app/file_manager_strings.grdp",
+    "//chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc",
+    "//ui/webui/resources/css/text_defaults.css",
     "check_select.js",
     "crostini.js",
     "js/strings.js",
diff --git a/ui/file_manager/file_manager/test/crostini.js b/ui/file_manager/file_manager/test/crostini.js
index 1f8a5a04..1e94667 100644
--- a/ui/file_manager/file_manager/test/crostini.js
+++ b/ui/file_manager/file_manager/test/crostini.js
@@ -133,7 +133,7 @@
       });
 };
 
-crostini.testErrorOpeningDownloadsWithCrostiniApp = (done) => {
+crostini.testShareBeforeOpeningDownloadsWithCrostiniApp = (done) => {
   // Save old fmp.getFileTasks and replace with version that returns
   // crostini app and chrome Text app.
   let oldGetFileTasks = chrome.fileManagerPrivate.getFileTasks;
@@ -152,11 +152,40 @@
     ]);
   };
 
-  test.setupAndWaitUntilReady()
+  // Save old fmp.sharePathWitCrostini.
+  const oldSharePath = chrome.fileManagerPrivate.sharePathWithCrostini;
+  let sharePathCalled = false;
+  chrome.fileManagerPrivate.sharePathWithCrostini = (entry, callback) => {
+    sharePathCalled = true;
+    oldSharePath(entry, callback);
+  };
+
+  // Save old fmp.executeTask.
+  const oldExecuteTask = chrome.fileManagerPrivate.executeTask;
+  let executeTaskCalled = false;
+  chrome.fileManagerPrivate.executeTask = (taskId, entries, callback) => {
+    executeTaskCalled = true;
+    oldExecuteTask(taskId, entries, callback);
+  };
+
+  test.setupAndWaitUntilReady([], [], [])
+      .then(() => {
+        // Add '/A', and '/A/hello.txt', refresh, 'A' is shown.
+        test.addEntries(
+            [test.ENTRIES.directoryA, test.ENTRIES.helloInA], [], []);
+        assertTrue(test.fakeMouseClick('#refresh-button'), 'click refresh');
+        return test.waitForFiles(
+            test.TestEntryInfo.getExpectedRows([test.ENTRIES.directoryA]));
+      })
+      .then(() => {
+        // Change to 'A' directory, hello.txt is shown.
+        assertTrue(test.fakeMouseDoubleClick('[file-name="A"]'));
+        return test.waitForFiles(
+            test.TestEntryInfo.getExpectedRows([test.ENTRIES.hello]));
+      })
       .then(() => {
         // Right click on 'hello.txt' file, wait for dialog with 'Open with'.
-        assertTrue(
-            test.fakeMouseRightClick('#listitem-' + test.maxListItemId()));
+        assertTrue(test.fakeMouseRightClick('[file-name="hello.txt"]'));
         return test.waitForElement(
             'cr-menu-item[command="#open-with"]:not([hidden]');
       })
@@ -167,7 +196,7 @@
       })
       .then(() => {
         // Ensure picker shows both options.  Click on 'Crostini App'.  Ensure
-        // error is shown.
+        // share path dialog is shown.
         const list = document.querySelectorAll('#default-tasks-list li div');
         assertEquals(2, list.length);
         assertEquals('Open with Crostini App', list[0].innerText);
@@ -175,27 +204,36 @@
         assertTrue(test.fakeMouseClick('#default-tasks-list li'));
         return test.repeatUntil(() => {
           return document.querySelector('.cr-dialog-title').innerText ===
-              'Unable to open with Crostini App' ||
-              test.pending('Waiting for Unable to open dialog');
+              'Share files with Linux' ||
+              test.pending('Waiting for share before open dialog');
         });
       })
       .then(() => {
-        // Validate error messages, click 'OK' to close.  Ensure dialog closes.
+        // Validate dialog messages, click 'OK' to share and open.  Ensure
+        // dialog closes.
         assertEquals(
-            'To open files with Crostini App, ' +
-                'first copy to Linux files folder.',
-            document.querySelector('.cr-dialog-text').innerText);
+            'Let Linux apps open <b>hello.txt</b>.',
+            document.querySelector('.cr-dialog-text').innerHTML);
         assertTrue(test.fakeMouseClick('button.cr-dialog-ok'));
         return test.waitForElementLost('.cr-dialog-container.shown');
       })
       .then(() => {
-        // Restore fmp.getFileTasks.
+        // Ensure fmp.sharePathWithCrostini, fmp.executeTask called.
+        return test.repeatUntil(() => {
+          return sharePathCalled && executeTaskCalled ||
+              test.pending('Waiting to share and open');
+        });
+      })
+      .then(() => {
+        // Restore fmp.*.
         chrome.fileManagerPrivate.getFileTasks = oldGetFileTasks;
+        chrome.fileManagerPrivate.sharePathWithCrostini = oldSharePath;
+        chrome.fileManagerPrivate.executeTask = oldExecuteTask;
         done();
       });
 };
 
-crostini.testErrorOpeningDownloadsWithDefaultCrostiniApp = (done) => {
+crostini.testErrorOpeningDownloadsRootWithDefaultCrostiniApp = (done) => {
   // Save old fmp.getFileTasks and replace with version that returns
   // crostini app and chrome Text app.
   let oldGetFileTasks = chrome.fileManagerPrivate.getFileTasks;
@@ -247,9 +285,11 @@
 };
 
 crostini.testSharePathCrostiniSuccess = (done) => {
+  const oldSharePath = chrome.fileManagerPrivate.sharePathWithCrostini;
   let sharePathCalled = false;
-  chrome.fileManagerPrivate.sharePathWithCrostini = (callback) => {
+  chrome.fileManagerPrivate.sharePathWithCrostini = (entry, callback) => {
     sharePathCalled = true;
+    oldSharePath(entry, callback);
   };
   test.setupAndWaitUntilReady()
       .then(() => {
@@ -273,6 +313,7 @@
       .then(() => {
         // Check sharePathWithCrostini is called.
         assertTrue(sharePathCalled);
+        chrome.fileManagerPrivate.sharePathWithCrostini = oldSharePath;
         done();
       });
 };
diff --git a/ui/file_manager/file_manager/test/js/test_util.js b/ui/file_manager/file_manager/test/js/test_util.js
index 4535c59..7ba16fb9 100644
--- a/ui/file_manager/file_manager/test/js/test_util.js
+++ b/ui/file_manager/file_manager/test/js/test_util.js
@@ -236,6 +236,11 @@
       test.EntryType.FILE, 'text.txt', 'hello.mhtml', 'text/html',
       test.SharedOption.NONE, 'Sep 4, 1998, 12:34 PM', 'hello.mhtml',
       '51 bytes', 'HTML document'),
+
+  helloInA: new test.TestEntryInfo(
+      test.EntryType.FILE, 'text.txt', 'hello.txt', 'text/plain',
+      test.SharedOption.NONE, 'Sep 4, 1998, 12:34 PM', 'A/hello.txt',
+      '51 bytes', 'Plain text'),
 };
 
 /**
@@ -492,10 +497,17 @@
  * Opens a Files app's main window and waits until it is initialized. Fills
  * the window with initial files. Should be called for the first window only.
  *
+ * @param {Array<!test.TestEntryInfo>=} opt_downloads Entries for downloads.
+ * @param {Array<!test.TestEntryInfo>=} opt_drive Entries for drive.
+ * @param {Array<!test.TestEntryInfo>=} opt_crostini Entries for crostini.
  * @return {Promise} Promise to be fulfilled with the result object, which
  *     contains the file list.
  */
-test.setupAndWaitUntilReady = function() {
+test.setupAndWaitUntilReady = function(opt_downloads, opt_drive, opt_crostini) {
+  const entriesDownloads = opt_downloads || test.BASIC_LOCAL_ENTRY_SET;
+  const entriesDrive = opt_drive || test.BASIC_DRIVE_ENTRY_SET;
+  const entriesCrostini = opt_crostini || test.BASIC_CROSTINI_ENTRY_SET;
+
   // Copy some functions from test.util.sync and bind to main window.
   test.fakeMouseClick = test.util.sync.fakeMouseClick.bind(null, window);
   test.fakeMouseDoubleClick =
@@ -510,9 +522,7 @@
 
   return test.loadData()
       .then(() => {
-        test.addEntries(
-            test.BASIC_LOCAL_ENTRY_SET, test.BASIC_DRIVE_ENTRY_SET,
-            test.BASIC_CROSTINI_ENTRY_SET);
+        test.addEntries(entriesDownloads, entriesDrive, entriesCrostini);
         return test.waitForElement(
             '#directory-tree [volume-type-icon="downloads"]');
       })
@@ -523,7 +533,7 @@
                 '#refresh-button' :
                 '#directory-tree [volume-type-icon="downloads"]'));
         return test.waitForFiles(
-            test.TestEntryInfo.getExpectedRows(test.BASIC_LOCAL_ENTRY_SET));
+            test.TestEntryInfo.getExpectedRows(entriesDownloads));
       });
 };
 
diff --git a/ui/gfx/buffer_format_util.cc b/ui/gfx/buffer_format_util.cc
index f72941f..5e3de26a 100644
--- a/ui/gfx/buffer_format_util.cc
+++ b/ui/gfx/buffer_format_util.cc
@@ -11,26 +11,15 @@
 namespace gfx {
 namespace {
 
-const BufferFormat kBufferFormats[] = {BufferFormat::ATC,
-                                       BufferFormat::ATCIA,
-                                       BufferFormat::DXT1,
-                                       BufferFormat::DXT5,
-                                       BufferFormat::ETC1,
-                                       BufferFormat::R_8,
-                                       BufferFormat::R_16,
-                                       BufferFormat::RG_88,
-                                       BufferFormat::BGR_565,
-                                       BufferFormat::RGBA_4444,
-                                       BufferFormat::RGBX_8888,
-                                       BufferFormat::RGBA_8888,
-                                       BufferFormat::BGRX_8888,
-                                       BufferFormat::BGRX_1010102,
-                                       BufferFormat::RGBX_1010102,
-                                       BufferFormat::BGRA_8888,
-                                       BufferFormat::RGBA_F16,
-                                       BufferFormat::UYVY_422,
-                                       BufferFormat::YUV_420_BIPLANAR,
-                                       BufferFormat::YVU_420};
+const BufferFormat kBufferFormats[] = {
+    BufferFormat::R_8,          BufferFormat::R_16,
+    BufferFormat::RG_88,        BufferFormat::BGR_565,
+    BufferFormat::RGBA_4444,    BufferFormat::RGBX_8888,
+    BufferFormat::RGBA_8888,    BufferFormat::BGRX_8888,
+    BufferFormat::BGRX_1010102, BufferFormat::RGBX_1010102,
+    BufferFormat::BGRA_8888,    BufferFormat::RGBA_F16,
+    BufferFormat::UYVY_422,     BufferFormat::YUV_420_BIPLANAR,
+    BufferFormat::YVU_420};
 
 static_assert(arraysize(kBufferFormats) ==
                   (static_cast<int>(BufferFormat::LAST) + 1),
@@ -41,18 +30,6 @@
     size_t width, BufferFormat format, size_t plane, size_t* size_in_bytes) {
   base::CheckedNumeric<size_t> checked_size = width;
   switch (format) {
-    case BufferFormat::ATCIA:
-    case BufferFormat::DXT5:
-      DCHECK_EQ(0u, plane);
-      *size_in_bytes = width;
-      return true;
-    case BufferFormat::ATC:
-    case BufferFormat::DXT1:
-    case BufferFormat::ETC1:
-      DCHECK_EQ(0u, plane);
-      DCHECK_EQ(0u, width % 2);
-      *size_in_bytes = width / 2;
-      return true;
     case BufferFormat::R_8:
       checked_size += 3;
       if (!checked_size.IsValid())
@@ -109,11 +86,6 @@
 
 size_t NumberOfPlanesForBufferFormat(BufferFormat format) {
   switch (format) {
-    case BufferFormat::ATC:
-    case BufferFormat::ATCIA:
-    case BufferFormat::DXT1:
-    case BufferFormat::DXT5:
-    case BufferFormat::ETC1:
     case BufferFormat::R_8:
     case BufferFormat::R_16:
     case BufferFormat::RG_88:
@@ -139,11 +111,6 @@
 
 size_t SubsamplingFactorForBufferFormat(BufferFormat format, size_t plane) {
   switch (format) {
-    case BufferFormat::ATC:
-    case BufferFormat::ATCIA:
-    case BufferFormat::DXT1:
-    case BufferFormat::DXT5:
-    case BufferFormat::ETC1:
     case BufferFormat::R_8:
     case BufferFormat::R_16:
     case BufferFormat::RG_88:
@@ -214,11 +181,6 @@
                                    size_t plane) {
   DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format));
   switch (format) {
-    case BufferFormat::ATC:
-    case BufferFormat::ATCIA:
-    case BufferFormat::DXT1:
-    case BufferFormat::DXT5:
-    case BufferFormat::ETC1:
     case BufferFormat::R_8:
     case BufferFormat::R_16:
     case BufferFormat::RG_88:
@@ -252,16 +214,6 @@
 
 const char* BufferFormatToString(BufferFormat format) {
   switch (format) {
-    case BufferFormat::ATC:
-      return "ATC";
-    case BufferFormat::ATCIA:
-      return "ATCIA";
-    case BufferFormat::DXT1:
-      return "DXT1";
-    case BufferFormat::DXT5:
-      return "DXT5";
-    case BufferFormat::ETC1:
-      return "ETC1";
     case BufferFormat::R_8:
       return "R_8";
     case BufferFormat::R_16:
diff --git a/ui/gfx/buffer_types.h b/ui/gfx/buffer_types.h
index 47c8b60..be72cf74 100644
--- a/ui/gfx/buffer_types.h
+++ b/ui/gfx/buffer_types.h
@@ -12,11 +12,6 @@
 // The format needs to be taken into account when mapping a buffer into the
 // client's address space.
 enum class BufferFormat {
-  ATC,
-  ATCIA,
-  DXT1,
-  DXT5,
-  ETC1,
   R_8,
   R_16,
   RG_88,
diff --git a/ui/gfx/geometry/rect_conversions.cc b/ui/gfx/geometry/rect_conversions.cc
index 3a5b2dc..43d866f 100644
--- a/ui/gfx/geometry/rect_conversions.cc
+++ b/ui/gfx/geometry/rect_conversions.cc
@@ -12,6 +12,20 @@
 
 namespace gfx {
 
+namespace {
+
+int ToFlooredIntIgnoringError(float f, float error) {
+  int rounded = ToRoundedInt(f);
+  return std::abs(rounded - f) < error ? rounded : ToFlooredInt(f);
+}
+
+int ToCeiledIntIgnoringError(float f, float error) {
+  int rounded = ToRoundedInt(f);
+  return std::abs(rounded - f) < error ? rounded : ToCeiledInt(f);
+}
+
+}  // anonymous namespace
+
 Rect ToEnclosingRect(const RectF& r) {
   int left = ToFlooredInt(r.x());
   int right = r.width() ? ToCeiledInt(r.right()) : left;
@@ -23,6 +37,17 @@
   return result;
 }
 
+Rect ToEnclosingRectIgnoringError(const RectF& r, float error) {
+  int left = ToFlooredIntIgnoringError(r.x(), error);
+  int right = r.width() ? ToCeiledIntIgnoringError(r.right(), error) : left;
+  int top = ToFlooredIntIgnoringError(r.y(), error);
+  int bottom = r.height() ? ToCeiledIntIgnoringError(r.bottom(), error) : top;
+
+  Rect result;
+  result.SetByBounds(left, top, right, bottom);
+  return result;
+}
+
 Rect ToEnclosedRect(const RectF& rect) {
   Rect result;
   result.SetByBounds(ToCeiledInt(rect.x()), ToCeiledInt(rect.y()),
diff --git a/ui/gfx/geometry/rect_conversions.h b/ui/gfx/geometry/rect_conversions.h
index 617074a..b8ef053 100644
--- a/ui/gfx/geometry/rect_conversions.h
+++ b/ui/gfx/geometry/rect_conversions.h
@@ -13,6 +13,13 @@
 // Returns the smallest Rect that encloses the given RectF.
 GFX_EXPORT Rect ToEnclosingRect(const RectF& rect);
 
+// Similar to ToEnclosingRect(), but for each edge, if the distance between the
+// edge and the nearest integer grid is smaller than |error|, the edge is
+// snapped to the integer grid. Unlike ToNearestRect() which only accepts
+// integer rect with or without floating point error, this function also accepts
+// non-integer rect.
+GFX_EXPORT Rect ToEnclosingRectIgnoringError(const RectF& rect, float error);
+
 // Returns the largest Rect that is enclosed by the given RectF.
 GFX_EXPORT Rect ToEnclosedRect(const RectF& rect);
 
diff --git a/ui/gfx/geometry/rect_unittest.cc b/ui/gfx/geometry/rect_unittest.cc
index 7acfb80..1f6d576 100644
--- a/ui/gfx/geometry/rect_unittest.cc
+++ b/ui/gfx/geometry/rect_unittest.cc
@@ -6,7 +6,7 @@
 
 #include <stddef.h>
 
-#include "base/macros.h"
+#include "base/stl_util.h"
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect.h"
@@ -40,7 +40,7 @@
     {0, 0, -10, -10, 0, 0, false},
   #endif
   };
-  for (size_t i = 0; i < arraysize(contains_cases); ++i) {
+  for (size_t i = 0; i < base::size(contains_cases); ++i) {
     const ContainsCase& value = contains_cases[i];
     Rect rect(value.rect_x, value.rect_y, value.rect_width, value.rect_height);
     EXPECT_EQ(value.contained, rect.Contains(value.point_x, value.point_y));
@@ -70,7 +70,7 @@
     { 10, 10, 10, 10, 20, 15, 10, 10, false },
     { 10, 10, 10, 10, 21, 15, 10, 10, false }
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
     Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
     EXPECT_EQ(tests[i].intersects, r1.Intersects(r2));
@@ -112,7 +112,7 @@
       0, 0, 2, 2,
       0, 0, 0, 0 }
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
     Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
     Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
@@ -161,7 +161,7 @@
       2, 2, 2, 2,
       2, 2, 2, 2 }
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
     Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
     Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
@@ -213,7 +213,7 @@
       0, 0, 3, 3,
       2, 2, 1, 1 }
   };
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
     Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
     Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
@@ -457,7 +457,7 @@
       std::numeric_limits<float>::max() }
   };
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
     RectF r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
 
@@ -496,9 +496,12 @@
       {{max_float, max_float, 2.0f, 2.0f}, {max_int, max_int, 0, 0}},
       {{0.0f, 0.0f, max_float, max_float}, {0, 0, max_int, max_int}},
       {{20000.5f, 20000.5f, 0.5f, 0.5f}, {20001, 20001, 0, 0}},
-      {{max_int_f, max_int_f, max_int_f, max_int_f}, {max_int, max_int, 0, 0}}};
+      {{max_int_f, max_int_f, max_int_f, max_int_f}, {max_int, max_int, 0, 0}},
+      {{1.9999f, 2.0002f, 5.9998f, 6.0001f}, {2, 3, 5, 5}},
+      {{1.9999f, 2.0001f, 6.0002f, 5.9998f}, {2, 3, 6, 4}},
+      {{1.9998f, 2.0002f, 6.0001f, 5.9999f}, {2, 3, 5, 5}}};
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     RectF source(tests[i].in.x, tests[i].in.y, tests[i].in.width,
                  tests[i].in.height);
     Rect enclosed = ToEnclosedRect(source);
@@ -556,9 +559,12 @@
       {{0.0f, 0.0f, max_float, max_float}, {0, 0, max_int, max_int}},
       {{20000.5f, 20000.5f, 0.5f, 0.5f}, {20000, 20000, 1, 1}},
       {{max_int_f, max_int_f, max_int_f, max_int_f}, {max_int, max_int, 0, 0}},
-      {{-0.5f, -0.5f, 22777712.f, 1.f}, {-1, -1, 22777713, 2}}};
+      {{-0.5f, -0.5f, 22777712.f, 1.f}, {-1, -1, 22777713, 2}},
+      {{1.9999f, 2.0002f, 5.9998f, 6.0001f}, {1, 2, 7, 7}},
+      {{1.9999f, 2.0001f, 6.0002f, 5.9998f}, {1, 2, 8, 6}},
+      {{1.9998f, 2.0002f, 6.0001f, 5.9999f}, {1, 2, 7, 7}}};
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     RectF source(tests[i].in.x, tests[i].in.y, tests[i].in.width,
                  tests[i].in.height);
 
@@ -585,6 +591,53 @@
   }
 }
 
+TEST(RectTest, ToEnclosingRectIgnoringError) {
+  static const int max_int = std::numeric_limits<int>::max();
+  static const float max_float = std::numeric_limits<float>::max();
+  static const float epsilon_float = std::numeric_limits<float>::epsilon();
+  static const float max_int_f = static_cast<float>(max_int);
+  static const float error = 0.001f;
+  static const struct Test {
+    struct {
+      float x;
+      float y;
+      float width;
+      float height;
+    } in;
+    struct {
+      int x;
+      int y;
+      int width;
+      int height;
+    } expected;
+  } tests[] = {
+      {{0.0f, 0.0f, 0.0f, 0.0f}, {0, 0, 0, 0}},
+      {{5.5f, 5.5f, 0.0f, 0.0f}, {5, 5, 0, 0}},
+      {{3.5f, 2.5f, epsilon_float, -0.0f}, {3, 2, 0, 0}},
+      {{3.5f, 2.5f, 0.f, 0.001f}, {3, 2, 0, 1}},
+      {{-1.5f, -1.5f, 3.0f, 3.0f}, {-2, -2, 4, 4}},
+      {{-1.5f, -1.5f, 3.5f, 3.5f}, {-2, -2, 4, 4}},
+      {{max_float, max_float, 2.0f, 2.0f}, {max_int, max_int, 0, 0}},
+      {{0.0f, 0.0f, max_float, max_float}, {0, 0, max_int, max_int}},
+      {{20000.5f, 20000.5f, 0.5f, 0.5f}, {20000, 20000, 1, 1}},
+      {{max_int_f, max_int_f, max_int_f, max_int_f}, {max_int, max_int, 0, 0}},
+      {{-0.5f, -0.5f, 22777712.f, 1.f}, {-1, -1, 22777713, 2}},
+      {{1.9999f, 2.0002f, 5.9998f, 6.0001f}, {2, 2, 6, 6}},
+      {{1.9999f, 2.0001f, 6.0002f, 5.9998f}, {2, 2, 6, 6}},
+      {{1.9998f, 2.0002f, 6.0001f, 5.9999f}, {2, 2, 6, 6}}};
+
+  for (size_t i = 0; i < base::size(tests); ++i) {
+    RectF source(tests[i].in.x, tests[i].in.y, tests[i].in.width,
+                 tests[i].in.height);
+
+    Rect enclosing = ToEnclosingRectIgnoringError(source, error);
+    EXPECT_EQ(tests[i].expected.x, enclosing.x());
+    EXPECT_EQ(tests[i].expected.y, enclosing.y());
+    EXPECT_EQ(tests[i].expected.width, enclosing.width());
+    EXPECT_EQ(tests[i].expected.height, enclosing.height());
+  }
+}
+
 TEST(RectTest, ToNearestRect) {
   Rect rect;
   EXPECT_EQ(rect, ToNearestRect(RectF(rect)));
@@ -617,7 +670,7 @@
       20000, 20000, 0, 0 },
   };
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
     Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
 
@@ -666,7 +719,7 @@
     }
   };
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     Rect result = ScaleToEnclosedRect(tests[i].input_rect,
                                       tests[i].input_scale);
     EXPECT_EQ(tests[i].expected_rect, result);
@@ -710,7 +763,7 @@
     }
   };
 
-  for (size_t i = 0; i < arraysize(tests); ++i) {
+  for (size_t i = 0; i < base::size(tests); ++i) {
     Rect result =
         ScaleToEnclosingRect(tests[i].input_rect, tests[i].input_scale);
     EXPECT_EQ(tests[i].expected_rect, result);
@@ -760,7 +813,7 @@
     { Point(-4, 6), Point(6, -4), Rect(-4, -4, 10, 10) },
   };
 
-  for (size_t i = 0; i < arraysize(int_tests); ++i) {
+  for (size_t i = 0; i < base::size(int_tests); ++i) {
     Rect actual = BoundingRect(int_tests[i].a, int_tests[i].b);
     EXPECT_EQ(int_tests[i].expected, actual);
   }
@@ -797,7 +850,7 @@
       RectF(-4.2f, -4.2f, 11.0f, 11.0f) }
   };
 
-  for (size_t i = 0; i < arraysize(float_tests); ++i) {
+  for (size_t i = 0; i < base::size(float_tests); ++i) {
     RectF actual = BoundingRect(float_tests[i].a, float_tests[i].b);
     EXPECT_RECTF_EQ(float_tests[i].expected, actual);
   }
diff --git a/ui/gfx/mac/io_surface.cc b/ui/gfx/mac/io_surface.cc
index 00ad38d..8d9f38b1 100644
--- a/ui/gfx/mac/io_surface.cc
+++ b/ui/gfx/mac/io_surface.cc
@@ -52,11 +52,6 @@
     case gfx::BufferFormat::UYVY_422:
       DCHECK_EQ(plane, 0);
       return 2;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::BGR_565:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBX_8888:
@@ -88,11 +83,6 @@
       return '2vuy';
     case gfx::BufferFormat::R_16:
     case gfx::BufferFormat::RG_88:
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::BGR_565:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBX_8888:
diff --git a/ui/gfx/mojo/buffer_types.mojom b/ui/gfx/mojo/buffer_types.mojom
index c14e5ae..170f1eb 100644
--- a/ui/gfx/mojo/buffer_types.mojom
+++ b/ui/gfx/mojo/buffer_types.mojom
@@ -6,11 +6,6 @@
 
 // gfx::BufferFormat
 enum BufferFormat {
-  ATC,
-  ATCIA,
-  DXT1,
-  DXT5,
-  ETC1,
   R_8,
   R_16,
   RG_88,
diff --git a/ui/gfx/mojo/buffer_types_struct_traits.h b/ui/gfx/mojo/buffer_types_struct_traits.h
index 33069bc2..8c8c1fc9 100644
--- a/ui/gfx/mojo/buffer_types_struct_traits.h
+++ b/ui/gfx/mojo/buffer_types_struct_traits.h
@@ -15,16 +15,6 @@
 struct EnumTraits<gfx::mojom::BufferFormat, gfx::BufferFormat> {
   static gfx::mojom::BufferFormat ToMojom(gfx::BufferFormat format) {
     switch (format) {
-      case gfx::BufferFormat::ATC:
-        return gfx::mojom::BufferFormat::ATC;
-      case gfx::BufferFormat::ATCIA:
-        return gfx::mojom::BufferFormat::ATCIA;
-      case gfx::BufferFormat::DXT1:
-        return gfx::mojom::BufferFormat::DXT1;
-      case gfx::BufferFormat::DXT5:
-        return gfx::mojom::BufferFormat::DXT5;
-      case gfx::BufferFormat::ETC1:
-        return gfx::mojom::BufferFormat::ETC1;
       case gfx::BufferFormat::R_8:
         return gfx::mojom::BufferFormat::R_8;
       case gfx::BufferFormat::R_16:
@@ -63,21 +53,6 @@
   static bool FromMojom(gfx::mojom::BufferFormat input,
                         gfx::BufferFormat* out) {
     switch (input) {
-      case gfx::mojom::BufferFormat::ATC:
-        *out = gfx::BufferFormat::ATC;
-        return true;
-      case gfx::mojom::BufferFormat::ATCIA:
-        *out = gfx::BufferFormat::ATCIA;
-        return true;
-      case gfx::mojom::BufferFormat::DXT1:
-        *out = gfx::BufferFormat::DXT1;
-        return true;
-      case gfx::mojom::BufferFormat::DXT5:
-        *out = gfx::BufferFormat::DXT5;
-        return true;
-      case gfx::mojom::BufferFormat::ETC1:
-        *out = gfx::BufferFormat::ETC1;
-        return true;
       case gfx::mojom::BufferFormat::R_8:
         *out = gfx::BufferFormat::R_8;
         return true;
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index c92de71..77eae44 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -51,6 +51,8 @@
   output_name = "gl_wrapper"  # Avoid colliding with OS X"s libGL.dylib.
 
   sources = [
+    "android/android_surface_composer_compat.cc",
+    "android/android_surface_composer_compat.h",
     "android/scoped_java_surface.cc",
     "android/scoped_java_surface.h",
     "android/surface_texture.cc",
@@ -195,6 +197,8 @@
       sources += [
         "gl_image_ahardwarebuffer.cc",
         "gl_image_ahardwarebuffer.h",
+        "gl_surface_egl_surface_control.cc",
+        "gl_surface_egl_surface_control.h",
       ]
 
       if (use_static_angle) {
diff --git a/ui/gl/android/android_surface_composer_compat.cc b/ui/gl/android/android_surface_composer_compat.cc
new file mode 100644
index 0000000..f34d25c
--- /dev/null
+++ b/ui/gl/android/android_surface_composer_compat.cc
@@ -0,0 +1,253 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gl/android/android_surface_composer_compat.h"
+
+#include "base/android/build_info.h"
+#include "base/memory/ptr_util.h"
+#include "base/no_destructor.h"
+
+#include <dlfcn.h>
+
+extern "C" {
+// ASurfaceComposer
+using pASurfaceComposer_Create = ASurfaceComposer* (*)(ANativeWindow*);
+using pASurfaceComposer_Delete = void (*)(ASurfaceComposer*);
+
+// ASurface
+using pASurfaceComposer_CreateSurface = ASurface* (*)(ASurfaceComposer*,
+                                                      int32_t content_type,
+                                                      ASurface* parent,
+                                                      const char* name);
+using pASurfaceComposer_DeleteSurface = void (*)(ASurface*);
+
+// ASurfaceTransaction
+using pASurfaceComposer_CreateTransaction = ASurfaceTransaction* (*)(void);
+using pASurfaceComposer_DeleteTransaction = void (*)(ASurfaceTransaction*);
+using pASurfaceComposer_TransactionApply = int64_t (*)(ASurfaceTransaction*);
+using pASurfaceComposer_TransactionSetVisibility =
+    void (*)(ASurfaceTransaction*, ASurface*, bool show);
+using pASurfaceComposer_TransactionSetPosition = void (*)(ASurfaceTransaction*,
+                                                          ASurface*,
+                                                          float x,
+                                                          float y);
+using pASurfaceComposer_TransactionSetZOrder =
+    void (*)(ASurfaceTransaction* transaction, ASurface*, int32_t z);
+using pASurfaceComposer_TransactionSetBuffer =
+    void (*)(ASurfaceTransaction* transaction,
+             ASurface*,
+             AHardwareBuffer*,
+             int32_t fence_fd);
+using pASurfaceComposer_TransactionSetSize =
+    void (*)(ASurfaceTransaction* transaction,
+             ASurface* surface,
+             uint32_t width,
+             uint32_t height);
+using pASurfaceComposer_TransactionSetCropRect =
+    void (*)(ASurfaceTransaction* transaction,
+             ASurface* surface,
+             int32_t left,
+             int32_t top,
+             int32_t right,
+             int32_t bottom);
+using pASurfaceComposer_TransactionSetOpaque =
+    void (*)(ASurfaceTransaction* transaction,
+             ASurface* surface,
+             uint32_t transform);
+}
+
+namespace gl {
+namespace {
+
+#define LOAD_FUNCTION(lib, func)                             \
+  do {                                                       \
+    func##Fn = reinterpret_cast<p##func>(dlsym(lib, #func)); \
+    if (!func##Fn) {                                         \
+      supported = false;                                     \
+      LOG(ERROR) << "Unable to load function " << #func;     \
+    }                                                        \
+  } while (0)
+
+struct SurfaceComposerMethods {
+ public:
+  static const SurfaceComposerMethods& Get() {
+    static const base::NoDestructor<SurfaceComposerMethods> instance;
+    return *instance;
+  }
+
+  SurfaceComposerMethods() {
+    void* main_dl_handle = dlopen(nullptr, RTLD_NOW);
+    if (!main_dl_handle) {
+      LOG(ERROR) << "Couldnt load android so";
+      supported = false;
+      return;
+    }
+
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_Create);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_Delete);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_CreateSurface);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_DeleteSurface);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_CreateTransaction);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_DeleteTransaction);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionApply);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetVisibility);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetPosition);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetZOrder);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetBuffer);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetSize);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetCropRect);
+    LOAD_FUNCTION(main_dl_handle, ASurfaceComposer_TransactionSetOpaque);
+  }
+
+  ~SurfaceComposerMethods() = default;
+
+  bool supported = true;
+  pASurfaceComposer_Create ASurfaceComposer_CreateFn;
+  pASurfaceComposer_Delete ASurfaceComposer_DeleteFn;
+  pASurfaceComposer_CreateSurface ASurfaceComposer_CreateSurfaceFn;
+  pASurfaceComposer_DeleteSurface ASurfaceComposer_DeleteSurfaceFn;
+  pASurfaceComposer_CreateTransaction ASurfaceComposer_CreateTransactionFn;
+  pASurfaceComposer_DeleteTransaction ASurfaceComposer_DeleteTransactionFn;
+  pASurfaceComposer_TransactionApply ASurfaceComposer_TransactionApplyFn;
+  pASurfaceComposer_TransactionSetVisibility
+      ASurfaceComposer_TransactionSetVisibilityFn;
+  pASurfaceComposer_TransactionSetPosition
+      ASurfaceComposer_TransactionSetPositionFn;
+  pASurfaceComposer_TransactionSetZOrder
+      ASurfaceComposer_TransactionSetZOrderFn;
+  pASurfaceComposer_TransactionSetBuffer
+      ASurfaceComposer_TransactionSetBufferFn;
+  pASurfaceComposer_TransactionSetSize ASurfaceComposer_TransactionSetSizeFn;
+  pASurfaceComposer_TransactionSetCropRect
+      ASurfaceComposer_TransactionSetCropRectFn;
+  pASurfaceComposer_TransactionSetOpaque
+      ASurfaceComposer_TransactionSetOpaqueFn;
+};
+};
+
+// static
+bool SurfaceComposer::IsSupported() {
+  const int sdk_int = base::android::BuildInfo::GetInstance()->sdk_int();
+  if (sdk_int < 29) {
+    LOG(ERROR) << "SurfaceControl not supported on sdk: " << sdk_int;
+    return false;
+  }
+  return SurfaceComposerMethods::Get().supported;
+}
+
+// static
+std::unique_ptr<SurfaceComposer> SurfaceComposer::Create(
+    ANativeWindow* window) {
+  DCHECK(SurfaceComposerMethods::Get().supported);
+  auto* a_composer =
+      SurfaceComposerMethods::Get().ASurfaceComposer_CreateFn(window);
+  if (!a_composer)
+    return nullptr;
+  return base::WrapUnique(new SurfaceComposer(a_composer));
+}
+
+SurfaceComposer::SurfaceComposer(ASurfaceComposer* composer)
+    : composer_(composer) {}
+
+SurfaceComposer::~SurfaceComposer() {
+  SurfaceComposerMethods::Get().ASurfaceComposer_DeleteFn(composer_);
+}
+
+SurfaceComposer::Surface::Surface() = default;
+
+SurfaceComposer::Surface::Surface(SurfaceComposer* composer,
+                                  SurfaceContentType content_type,
+                                  const char* name,
+                                  Surface* parent) {
+  surface_ = SurfaceComposerMethods::Get().ASurfaceComposer_CreateSurfaceFn(
+      composer->composer_, static_cast<int32_t>(content_type),
+      parent ? parent->surface() : nullptr, name);
+  DCHECK(surface_);
+}
+
+SurfaceComposer::Surface::~Surface() {
+  if (surface_)
+    SurfaceComposerMethods::Get().ASurfaceComposer_DeleteSurfaceFn(surface_);
+}
+
+SurfaceComposer::Surface::Surface(Surface&& other) {
+  surface_ = other.surface_;
+  other.surface_ = nullptr;
+}
+
+SurfaceComposer::Surface& SurfaceComposer::Surface::operator=(Surface&& other) {
+  if (surface_)
+    SurfaceComposerMethods::Get().ASurfaceComposer_DeleteSurfaceFn(surface_);
+
+  surface_ = other.surface_;
+  other.surface_ = nullptr;
+  return *this;
+}
+
+SurfaceComposer::Transaction::Transaction() {
+  transaction_ =
+      SurfaceComposerMethods::Get().ASurfaceComposer_CreateTransactionFn();
+  DCHECK(transaction_);
+}
+
+SurfaceComposer::Transaction::~Transaction() {
+  SurfaceComposerMethods::Get().ASurfaceComposer_DeleteTransactionFn(
+      transaction_);
+}
+
+void SurfaceComposer::Transaction::SetVisibility(const Surface& surface,
+                                                 bool show) {
+  SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetVisibilityFn(
+      transaction_, surface.surface(), show);
+}
+
+void SurfaceComposer::Transaction::SetPosition(const Surface& surface,
+                                               float x,
+                                               float y) {
+  SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetPositionFn(
+      transaction_, surface.surface(), x, y);
+}
+
+void SurfaceComposer::Transaction::SetZOrder(const Surface& surface,
+                                             int32_t z) {
+  SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetZOrderFn(
+      transaction_, surface.surface(), z);
+}
+
+void SurfaceComposer::Transaction::SetBuffer(const Surface& surface,
+                                             AHardwareBuffer* buffer,
+                                             base::ScopedFD fence_fd) {
+  SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetBufferFn(
+      transaction_, surface.surface(), buffer,
+      fence_fd.is_valid() ? fence_fd.release() : -1);
+}
+
+void SurfaceComposer::Transaction::SetSize(const Surface& surface,
+                                           uint32_t width,
+                                           uint32_t height) {
+  SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetSizeFn(
+      transaction_, surface.surface(), width, height);
+}
+
+void SurfaceComposer::Transaction::SetCropRect(const Surface& surface,
+                                               int32_t left,
+                                               int32_t top,
+                                               int32_t right,
+                                               int32_t bottom) {
+  SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetCropRectFn(
+      transaction_, surface.surface(), left, top, right, bottom);
+}
+
+void SurfaceComposer::Transaction::SetOpaque(const Surface& surface,
+                                             bool opaque) {
+  SurfaceComposerMethods::Get().ASurfaceComposer_TransactionSetOpaqueFn(
+      transaction_, surface.surface(), opaque);
+}
+
+void SurfaceComposer::Transaction::Apply() {
+  SurfaceComposerMethods::Get().ASurfaceComposer_TransactionApplyFn(
+      transaction_);
+}
+
+}  // namespace gl
diff --git a/ui/gl/android/android_surface_composer_compat.h b/ui/gl/android/android_surface_composer_compat.h
new file mode 100644
index 0000000..05b6c87
--- /dev/null
+++ b/ui/gl/android/android_surface_composer_compat.h
@@ -0,0 +1,86 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GL_ANDROID_ANDROID_SURFACE_COMPOSER_COMPAT_H_
+#define UI_GL_ANDROID_ANDROID_SURFACE_COMPOSER_COMPAT_H_
+
+#include <memory>
+
+#include <android/hardware_buffer.h>
+#include <android/native_window.h>
+
+#include "base/files/scoped_file.h"
+#include "ui/gl/gl_export.h"
+
+extern "C" {
+typedef struct ASurface ASurface;
+typedef struct ASurfaceComposer ASurfaceComposer;
+typedef struct ASurfaceTransaction ASurfaceTransaction;
+}
+
+namespace gl {
+
+class GL_EXPORT SurfaceComposer {
+ public:
+  enum class SurfaceContentType : int32_t {
+    kNone = 0,
+    kAHardwareBuffer = 1,
+  };
+
+  class GL_EXPORT Surface {
+   public:
+    Surface();
+    Surface(SurfaceComposer* composer,
+            SurfaceContentType content_type,
+            const char* name,
+            Surface* parent = nullptr);
+    ~Surface();
+
+    Surface(Surface&& other);
+    Surface& operator=(Surface&& other);
+
+    ASurface* surface() const { return surface_; }
+
+   private:
+    ASurface* surface_ = nullptr;
+  };
+
+  class GL_EXPORT Transaction {
+   public:
+    Transaction();
+    ~Transaction();
+
+    void SetVisibility(const Surface& surface, bool show);
+    void SetPosition(const Surface& surface, float x, float y);
+    void SetZOrder(const Surface& surface, int32_t z);
+    void SetBuffer(const Surface& surface,
+                   AHardwareBuffer* buffer,
+                   base::ScopedFD fence_fd);
+    void SetSize(const Surface& surface, uint32_t width, uint32_t height);
+    void SetCropRect(const Surface& surface,
+                     int32_t left,
+                     int32_t top,
+                     int32_t right,
+                     int32_t bottom);
+    void SetOpaque(const Surface& surface, bool opaque);
+    void Apply();
+
+   private:
+    ASurfaceTransaction* transaction_;
+  };
+
+  static bool IsSupported();
+
+  static std::unique_ptr<SurfaceComposer> Create(ANativeWindow* window);
+  ~SurfaceComposer();
+
+ private:
+  explicit SurfaceComposer(ASurfaceComposer* composer);
+
+  ASurfaceComposer* composer_;
+};
+
+};  // namespace gl
+
+#endif  // UI_GL_ANDROID_ANDROID_SURFACE_COMPOSER_COMPAT_H_
diff --git a/ui/gl/gl_image.h b/ui/gl/gl_image.h
index ecf8f01..3402173 100644
--- a/ui/gl/gl_image.h
+++ b/ui/gl/gl_image.h
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "build/build_config.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
@@ -105,7 +106,7 @@
   virtual bool EmulatingRGB() const;
 
   // An identifier for subclasses. Necessary for safe downcasting.
-  enum class Type { NONE, MEMORY, IOSURFACE, DXGI_IMAGE };
+  enum class Type { NONE, MEMORY, IOSURFACE, DXGI_IMAGE, A_HARDWARE_BUFFER };
   virtual Type GetType() const;
 
  protected:
diff --git a/ui/gl/gl_image_ahardwarebuffer.cc b/ui/gl/gl_image_ahardwarebuffer.cc
index 273f3ac..f6530e65 100644
--- a/ui/gl/gl_image_ahardwarebuffer.cc
+++ b/ui/gl/gl_image_ahardwarebuffer.cc
@@ -15,6 +15,7 @@
 
 bool GLImageAHardwareBuffer::Initialize(AHardwareBuffer* buffer,
                                         bool preserved) {
+  handle_ = base::android::ScopedHardwareBufferHandle::Create(buffer);
   EGLint attribs[] = {EGL_IMAGE_PRESERVED_KHR, preserved ? EGL_TRUE : EGL_FALSE,
                       EGL_NONE};
   EGLClientBuffer client_buffer = eglGetNativeClientBufferANDROID(buffer);
@@ -54,4 +55,15 @@
     uint64_t process_tracing_id,
     const std::string& dump_name) {}
 
+GLImage::Type GLImageAHardwareBuffer::GetType() const {
+  return Type::A_HARDWARE_BUFFER;
+}
+
+// static
+GLImageAHardwareBuffer* GLImageAHardwareBuffer::FromGLImage(GLImage* image) {
+  if (image->GetType() != Type::A_HARDWARE_BUFFER)
+    return nullptr;
+  return static_cast<GLImageAHardwareBuffer*>(image);
+}
+
 }  // namespace gl
diff --git a/ui/gl/gl_image_ahardwarebuffer.h b/ui/gl/gl_image_ahardwarebuffer.h
index a6245263..9eb1583d 100644
--- a/ui/gl/gl_image_ahardwarebuffer.h
+++ b/ui/gl/gl_image_ahardwarebuffer.h
@@ -5,6 +5,7 @@
 #ifndef UI_GL_GL_IMAGE_AHARDWAREBUFFER_H_
 #define UI_GL_GL_IMAGE_AHARDWAREBUFFER_H_
 
+#include "base/android/scoped_hardware_buffer_handle.h"
 #include "base/macros.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_export.h"
@@ -18,6 +19,9 @@
 
   // Create an EGLImage from a given Android hardware buffer.
   bool Initialize(AHardwareBuffer* buffer, bool preserved);
+  const base::android::ScopedHardwareBufferHandle& handle() const {
+    return handle_;
+  }
 
   // Overridden from GLImage:
   unsigned GetInternalFormat() override;
@@ -37,11 +41,17 @@
   void OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
                     uint64_t process_tracing_id,
                     const std::string& dump_name) override;
+  Type GetType() const override;
+
+  // Downcasts from |image|. Returns |nullptr| on failure.
+  static GLImageAHardwareBuffer* FromGLImage(GLImage* image);
 
  protected:
   ~GLImageAHardwareBuffer() override;
 
  private:
+  base::android::ScopedHardwareBufferHandle handle_;
+
   DISALLOW_COPY_AND_ASSIGN(GLImageAHardwareBuffer);
 };
 
diff --git a/ui/gl/gl_image_io_surface.mm b/ui/gl/gl_image_io_surface.mm
index 2bfff15..5c846561 100644
--- a/ui/gl/gl_image_io_surface.mm
+++ b/ui/gl/gl_image_io_surface.mm
@@ -78,11 +78,6 @@
       // OpenGL ES 3.0, for the case) support only GL_RGBA (the hardware ignores
       // the alpha channel anyway), see https://crbug.com/797347.
       return GL_RGBA;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::BGR_565:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBX_8888:
@@ -113,11 +108,6 @@
       return GL_RGBA;
     case gfx::BufferFormat::UYVY_422:
       return GL_YCBCR_422_APPLE;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::BGR_565:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBX_8888:
@@ -149,11 +139,6 @@
       return GL_HALF_APPLE;
     case gfx::BufferFormat::UYVY_422:
       return GL_UNSIGNED_SHORT_8_8_APPLE;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::BGR_565:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBX_8888:
@@ -514,11 +499,6 @@
       return true;
     case gfx::BufferFormat::R_16:
     case gfx::BufferFormat::RG_88:
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::BGR_565:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBX_8888:
diff --git a/ui/gl/gl_image_io_surface_egl.mm b/ui/gl/gl_image_io_surface_egl.mm
index b637ecc..690af44d 100644
--- a/ui/gl/gl_image_io_surface_egl.mm
+++ b/ui/gl/gl_image_io_surface_egl.mm
@@ -50,11 +50,6 @@
     case gfx::BufferFormat::BGRX_1010102:
       NOTIMPLEMENTED();
       return {GL_NONE, GL_NONE};
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::BGR_565:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::RGBX_8888:
diff --git a/ui/gl/gl_image_memory.cc b/ui/gl/gl_image_memory.cc
index 3b44a540..26bc08d 100644
--- a/ui/gl/gl_image_memory.cc
+++ b/ui/gl/gl_image_memory.cc
@@ -23,11 +23,6 @@
 
 bool ValidInternalFormat(unsigned internalformat) {
   switch (internalformat) {
-    case GL_ATC_RGB_AMD:
-    case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD:
-    case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-    case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-    case GL_ETC1_RGB8_OES:
     case GL_RED:
     case GL_RG:
     case GL_RGB:
@@ -40,50 +35,8 @@
   }
 }
 
-bool IsCompressedFormat(gfx::BufferFormat format) {
-  switch (format) {
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
-      return true;
-    case gfx::BufferFormat::R_8:
-    case gfx::BufferFormat::R_16:
-    case gfx::BufferFormat::RG_88:
-    case gfx::BufferFormat::BGR_565:
-    case gfx::BufferFormat::RGBA_4444:
-    case gfx::BufferFormat::RGBX_8888:
-    case gfx::BufferFormat::RGBA_8888:
-    case gfx::BufferFormat::BGRX_8888:
-    case gfx::BufferFormat::BGRX_1010102:
-    case gfx::BufferFormat::RGBX_1010102:
-    case gfx::BufferFormat::BGRA_8888:
-    case gfx::BufferFormat::RGBA_F16:
-      return false;
-    case gfx::BufferFormat::YVU_420:
-    case gfx::BufferFormat::YUV_420_BIPLANAR:
-    case gfx::BufferFormat::UYVY_422:
-      NOTREACHED();
-      return false;
-  }
-
-  NOTREACHED();
-  return false;
-}
-
 GLenum TextureFormat(gfx::BufferFormat format) {
   switch (format) {
-    case gfx::BufferFormat::ATC:
-      return GL_ATC_RGB_AMD;
-    case gfx::BufferFormat::ATCIA:
-      return GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD;
-    case gfx::BufferFormat::DXT1:
-      return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
-    case gfx::BufferFormat::DXT5:
-      return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
-    case gfx::BufferFormat::ETC1:
-      return GL_ETC1_RGB8_OES;
     case gfx::BufferFormat::R_8:
       return GL_RED;
     case gfx::BufferFormat::R_16:
@@ -132,11 +85,6 @@
     case gfx::BufferFormat::R_8:
     case gfx::BufferFormat::R_16:
     case gfx::BufferFormat::RG_88:
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
       return TextureFormat(format);
     case gfx::BufferFormat::YVU_420:
     case gfx::BufferFormat::YUV_420_BIPLANAR:
@@ -169,11 +117,6 @@
     case gfx::BufferFormat::BGRX_1010102:
     case gfx::BufferFormat::RGBX_1010102:
       return GL_UNSIGNED_INT_2_10_10_10_REV;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::YVU_420:
     case gfx::BufferFormat::YUV_420_BIPLANAR:
     case gfx::BufferFormat::UYVY_422:
@@ -203,11 +146,6 @@
       return base::checked_cast<GLint>(stride) / 8;
     case gfx::BufferFormat::R_8:
       return base::checked_cast<GLint>(stride);
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::YVU_420:
     case gfx::BufferFormat::YUV_420_BIPLANAR:
     case gfx::BufferFormat::UYVY_422:
@@ -335,12 +273,6 @@
       *data_row_length = size.width();
       return gles2_data;
     }
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
-      return nullptr;  // No data conversion needed
     case gfx::BufferFormat::YVU_420:
     case gfx::BufferFormat::YUV_420_BIPLANAR:
     case gfx::BufferFormat::UYVY_422:
@@ -391,8 +323,6 @@
 
   DCHECK(memory);
   DCHECK(!memory_);
-  DCHECK(!IsCompressedFormat(format) || size_.width() % 4 == 0);
-  DCHECK(!IsCompressedFormat(format) || size_.height() % 4 == 0);
   memory_ = memory;
   format_ = format;
   stride_ = stride;
@@ -419,33 +349,26 @@
   if (target == GL_TEXTURE_EXTERNAL_OES)
     return false;
 
-  if (IsCompressedFormat(format_)) {
-    glCompressedTexImage2D(
-        target, 0, TextureFormat(format_), size_.width(), size_.height(), 0,
-        static_cast<GLsizei>(BufferSizeForBufferFormat(size_, format_)),
-        memory_);
-  } else {
-    GLenum data_format = DataFormat(format_);
-    GLenum data_type = DataType(format_);
-    GLint data_row_length = DataRowLength(stride_, format_);
-    std::unique_ptr<uint8_t[]> gles2_data;
+  GLenum data_format = DataFormat(format_);
+  GLenum data_type = DataType(format_);
+  GLint data_row_length = DataRowLength(stride_, format_);
+  std::unique_ptr<uint8_t[]> gles2_data;
 
-    if (GLContext::GetCurrent()->GetVersionInfo()->is_es) {
-      gles2_data = GLES2Data(size_, format_, stride_, memory_, &data_format,
-                             &data_type, &data_row_length);
-    }
-
-    if (data_row_length != size_.width())
-      glPixelStorei(GL_UNPACK_ROW_LENGTH, data_row_length);
-
-    glTexImage2D(target, 0, TextureFormat(format_), size_.width(),
-                 size_.height(), 0, data_format, data_type,
-                 gles2_data ? gles2_data.get() : memory_);
-
-    if (data_row_length != size_.width())
-      glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+  if (GLContext::GetCurrent()->GetVersionInfo()->is_es) {
+    gles2_data = GLES2Data(size_, format_, stride_, memory_, &data_format,
+                           &data_type, &data_row_length);
   }
 
+  if (data_row_length != size_.width())
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, data_row_length);
+
+  glTexImage2D(target, 0, TextureFormat(format_), size_.width(), size_.height(),
+               0, data_format, data_type,
+               gles2_data ? gles2_data.get() : memory_);
+
+  if (data_row_length != size_.width())
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
   return true;
 }
 
@@ -464,38 +387,26 @@
     return false;
 
   const uint8_t* data = memory_ + rect.y() * stride_;
-  if (IsCompressedFormat(format_)) {
-    // Height must be a multiple of 4.
-    if (rect.height() % 4)
-      return false;
+  GLenum data_format = DataFormat(format_);
+  GLenum data_type = DataType(format_);
+  GLint data_row_length = DataRowLength(stride_, format_);
+  std::unique_ptr<uint8_t[]> gles2_data;
 
-    glCompressedTexSubImage2D(
-        target, 0, offset.x(), offset.y(), rect.width(), rect.height(),
-        DataFormat(format_),
-        static_cast<GLsizei>(BufferSizeForBufferFormat(rect.size(), format_)),
-        data);
-  } else {
-    GLenum data_format = DataFormat(format_);
-    GLenum data_type = DataType(format_);
-    GLint data_row_length = DataRowLength(stride_, format_);
-    std::unique_ptr<uint8_t[]> gles2_data;
-
-    if (GLContext::GetCurrent()->GetVersionInfo()->is_es) {
-      gles2_data = GLES2Data(rect.size(), format_, stride_, data, &data_format,
-                             &data_type, &data_row_length);
-    }
-
-    if (data_row_length != rect.width())
-      glPixelStorei(GL_UNPACK_ROW_LENGTH, data_row_length);
-
-    glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(),
-                    rect.height(), data_format, data_type,
-                    gles2_data ? gles2_data.get() : data);
-
-    if (data_row_length != rect.width())
-      glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+  if (GLContext::GetCurrent()->GetVersionInfo()->is_es) {
+    gles2_data = GLES2Data(rect.size(), format_, stride_, data, &data_format,
+                           &data_type, &data_row_length);
   }
 
+  if (data_row_length != rect.width())
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, data_row_length);
+
+  glTexSubImage2D(target, 0, offset.x(), offset.y(), rect.width(),
+                  rect.height(), data_format, data_type,
+                  gles2_data ? gles2_data.get() : data);
+
+  if (data_row_length != rect.width())
+    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+
   return true;
 }
 
@@ -523,11 +434,6 @@
 // static
 bool GLImageMemory::ValidFormat(gfx::BufferFormat format) {
   switch (format) {
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::R_8:
     case gfx::BufferFormat::R_16:
     case gfx::BufferFormat::RG_88:
diff --git a/ui/gl/gl_image_native_pixmap.cc b/ui/gl/gl_image_native_pixmap.cc
index ceea2125..9ab046fa 100644
--- a/ui/gl/gl_image_native_pixmap.cc
+++ b/ui/gl/gl_image_native_pixmap.cc
@@ -89,11 +89,6 @@
       return DRM_FORMAT_YVU420;
     case gfx::BufferFormat::YUV_420_BIPLANAR:
       return DRM_FORMAT_NV12;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::BGRX_1010102:
     case gfx::BufferFormat::RGBA_F16:
@@ -412,11 +407,6 @@
       return GL_RGB_YCRCB_420_CHROMIUM;
     case gfx::BufferFormat::YUV_420_BIPLANAR:
       return GL_RGB_YCBCR_420V_CHROMIUM;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::BGRX_1010102:
     case gfx::BufferFormat::RGBA_F16:
@@ -444,11 +434,6 @@
     case gfx::BufferFormat::YVU_420:
     case gfx::BufferFormat::YUV_420_BIPLANAR:
       return true;
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::BGRX_1010102:
     case gfx::BufferFormat::RGBA_F16:
diff --git a/ui/gl/gl_surface_egl_surface_control.cc b/ui/gl/gl_surface_egl_surface_control.cc
new file mode 100644
index 0000000..48a0f57b
--- /dev/null
+++ b/ui/gl/gl_surface_egl_surface_control.cc
@@ -0,0 +1,205 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gl/gl_surface_egl_surface_control.h"
+
+#include "base/threading/thread_task_runner_handle.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gl/gl_fence_android_native_fence_sync.h"
+#include "ui/gl/gl_image_ahardwarebuffer.h"
+
+namespace gl {
+namespace {
+
+constexpr char kSurfaceName[] = "ChromeSurface";
+
+}  // namespace
+
+GLSurfaceEGLSurfaceControl::GLSurfaceEGLSurfaceControl(ANativeWindow* window) {
+  surface_composer_ = SurfaceComposer::Create(window);
+}
+
+GLSurfaceEGLSurfaceControl::~GLSurfaceEGLSurfaceControl() = default;
+
+bool GLSurfaceEGLSurfaceControl::Initialize(GLSurfaceFormat format) {
+  format_ = format;
+  return true;
+}
+
+void GLSurfaceEGLSurfaceControl::Destroy() {
+  pending_transaction_.reset();
+  surface_list_.clear();
+  surface_composer_.reset();
+}
+
+bool GLSurfaceEGLSurfaceControl::Resize(const gfx::Size& size,
+                                        float scale_factor,
+                                        ColorSpace color_space,
+                                        bool has_alpha) {
+  // Resizing requires resizing the SurfaceView in the browser.
+  return true;
+}
+
+bool GLSurfaceEGLSurfaceControl::IsOffscreen() {
+  return false;
+}
+
+gfx::SwapResult GLSurfaceEGLSurfaceControl::SwapBuffers(
+    const PresentationCallback& callback) {
+  DCHECK(pending_transaction_);
+
+  pending_transaction_->Apply();
+  pending_transaction_.reset();
+
+  DCHECK_GE(surface_list_.size(), pending_surfaces_count_);
+  surface_list_.resize(pending_surfaces_count_);
+  pending_surfaces_count_ = 0u;
+
+  // TODO(khushalsagar): Send the legit timestamp when hooking up transaction
+  // acks.
+  constexpr int64_t kRefreshIntervalInMicroseconds =
+      base::Time::kMicrosecondsPerSecond / 60;
+  gfx::PresentationFeedback feedback(
+      base::TimeTicks::Now(),
+      base::TimeDelta::FromMicroseconds(kRefreshIntervalInMicroseconds),
+      0 /* flags */);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(callback, feedback));
+
+  // TODO(khushalsagar): Need to hook up transaction ack from the framework to
+  // delay this ack.
+  return gfx::SwapResult::SWAP_ACK;
+}
+
+gfx::Size GLSurfaceEGLSurfaceControl::GetSize() {
+  return gfx::Size(0, 0);
+}
+
+bool GLSurfaceEGLSurfaceControl::OnMakeCurrent(GLContext* context) {
+  return true;
+}
+
+bool GLSurfaceEGLSurfaceControl::ScheduleOverlayPlane(
+    int z_order,
+    gfx::OverlayTransform transform,
+    GLImage* image,
+    const gfx::Rect& bounds_rect,
+    const gfx::RectF& crop_rect,
+    bool enable_blend,
+    std::unique_ptr<gfx::GpuFence> gpu_fence) {
+  if (!pending_transaction_)
+    pending_transaction_.emplace();
+
+  bool uninitialized = false;
+  if (pending_surfaces_count_ == surface_list_.size()) {
+    uninitialized = true;
+    surface_list_.emplace_back(surface_composer_.get());
+  }
+  pending_surfaces_count_++;
+  auto& surface_state = surface_list_.at(pending_surfaces_count_ - 1);
+
+  if (uninitialized || surface_state.z_order != z_order) {
+    surface_state.z_order = z_order;
+    pending_transaction_->SetZOrder(surface_state.surface, z_order);
+  }
+
+  if (uninitialized || surface_state.transform != transform) {
+    surface_state.transform = transform;
+    // TODO(khushalsagar): Forward the transform once the NDK API is in place.
+  }
+
+  auto* ahb_image = GLImageAHardwareBuffer::FromGLImage(image);
+  auto hardware_buffer =
+      ahb_image ? base::android::ScopedHardwareBufferHandle::Create(
+                      ahb_image->handle().get())
+                : base::android::ScopedHardwareBufferHandle();
+  if (uninitialized ||
+      surface_state.hardware_buffer.get() != hardware_buffer.get()) {
+    surface_state.hardware_buffer = std::move(hardware_buffer);
+
+    // TODO(khushalsagar): We are currently using the same fence for all
+    // overlays but that won't work for video frames where the fence needs to
+    // come from the media codec by AImageReader. The release of this buffer to
+    // the AImageReader also needs to be tied to the transaction callbacks.
+    base::ScopedFD fence_fd;
+    if (gpu_fence && surface_state.hardware_buffer.get()) {
+      auto fence_handle =
+          gfx::CloneHandleForIPC(gpu_fence->GetGpuFenceHandle());
+      DCHECK(!fence_handle.is_null());
+      fence_fd = base::ScopedFD(fence_handle.native_fd.fd);
+    }
+
+    pending_transaction_->SetBuffer(surface_state.surface,
+                                    surface_state.hardware_buffer.get(),
+                                    std::move(fence_fd));
+  }
+
+  if (uninitialized || surface_state.bounds_rect != bounds_rect) {
+    surface_state.bounds_rect = bounds_rect;
+    pending_transaction_->SetPosition(surface_state.surface, bounds_rect.x(),
+                                      bounds_rect.y());
+    pending_transaction_->SetSize(surface_state.surface, bounds_rect.width(),
+                                  bounds_rect.height());
+  }
+
+  // TODO(khushalsagar): Currently the framework refuses to the draw the buffer
+  // if the crop rect doesn't exactly match the buffer size. Update when fixed.
+  /*gfx::Rect enclosed_crop_rect = gfx::ToEnclosedRect(crop_rect);
+  if (uninitialized || surface_state.crop_rect != enclosed_crop_rect) {
+    surface_state.crop_rect = enclosed_crop_rect;
+    pending_transaction_->SetCropRect(
+        surface_state.surface, enclosed_crop_rect.x(), enclosed_crop_rect.y(),
+        enclosed_crop_rect.right(), enclosed_crop_rect.bottom());
+  }*/
+
+  bool opaque = !enable_blend;
+  if (uninitialized || surface_state.opaque != opaque) {
+    surface_state.opaque = opaque;
+    pending_transaction_->SetOpaque(surface_state.surface, opaque);
+  }
+
+  return true;
+}
+
+bool GLSurfaceEGLSurfaceControl::IsSurfaceless() const {
+  return true;
+}
+
+void* GLSurfaceEGLSurfaceControl::GetHandle() {
+  return nullptr;
+}
+
+bool GLSurfaceEGLSurfaceControl::SupportsPlaneGpuFences() const {
+  return true;
+}
+
+bool GLSurfaceEGLSurfaceControl::SupportsPresentationCallback() {
+  return true;
+}
+
+bool GLSurfaceEGLSurfaceControl::SupportsSwapBuffersWithBounds() {
+  // TODO(khushalsagar): Add support for partial swap.
+  return false;
+}
+
+bool GLSurfaceEGLSurfaceControl::SupportsCommitOverlayPlanes() {
+  return true;
+}
+
+GLSurfaceEGLSurfaceControl::SurfaceState::SurfaceState(
+    SurfaceComposer* composer)
+    : surface(composer,
+              SurfaceComposer::SurfaceContentType::kAHardwareBuffer,
+              kSurfaceName) {}
+
+GLSurfaceEGLSurfaceControl::SurfaceState::SurfaceState() = default;
+GLSurfaceEGLSurfaceControl::SurfaceState::SurfaceState(SurfaceState&& other) =
+    default;
+GLSurfaceEGLSurfaceControl::SurfaceState&
+GLSurfaceEGLSurfaceControl::SurfaceState::operator=(SurfaceState&& other) =
+    default;
+
+GLSurfaceEGLSurfaceControl::SurfaceState::~SurfaceState() = default;
+
+}  // namespace gl
diff --git a/ui/gl/gl_surface_egl_surface_control.h b/ui/gl/gl_surface_egl_surface_control.h
new file mode 100644
index 0000000..edd16b6
--- /dev/null
+++ b/ui/gl/gl_surface_egl_surface_control.h
@@ -0,0 +1,88 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GL_GL_SURFACE_EGL_SURFACE_CONTROL_H_
+#define UI_GL_GL_SURFACE_EGL_SURFACE_CONTROL_H_
+
+#include <android/native_window.h>
+
+#include "base/android/scoped_hardware_buffer_handle.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "ui/gl/android/android_surface_composer_compat.h"
+#include "ui/gl/gl_export.h"
+#include "ui/gl/gl_surface_egl.h"
+
+namespace gl {
+
+class GL_EXPORT GLSurfaceEGLSurfaceControl : public gl::GLSurfaceEGL {
+ public:
+  explicit GLSurfaceEGLSurfaceControl(ANativeWindow* window);
+
+  // GLSurface implementation.
+  bool Initialize(gl::GLSurfaceFormat format) override;
+  void Destroy() override;
+  bool Resize(const gfx::Size& size,
+              float scale_factor,
+              ColorSpace color_space,
+              bool has_alpha) override;
+  bool IsOffscreen() override;
+  gfx::SwapResult SwapBuffers(const PresentationCallback& callback) override;
+  gfx::Size GetSize() override;
+  bool OnMakeCurrent(gl::GLContext* context) override;
+  bool ScheduleOverlayPlane(int z_order,
+                            gfx::OverlayTransform transform,
+                            gl::GLImage* image,
+                            const gfx::Rect& bounds_rect,
+                            const gfx::RectF& crop_rect,
+                            bool enable_blend,
+                            std::unique_ptr<gfx::GpuFence> gpu_fence) override;
+  bool IsSurfaceless() const override;
+  void* GetHandle() override;
+
+  bool SupportsPlaneGpuFences() const override;
+  bool SupportsPresentationCallback() override;
+  bool SupportsSwapBuffersWithBounds() override;
+  bool SupportsCommitOverlayPlanes() override;
+
+ private:
+  ~GLSurfaceEGLSurfaceControl() override;
+
+  struct SurfaceState {
+    SurfaceState();
+    explicit SurfaceState(gl::SurfaceComposer* composer);
+    ~SurfaceState();
+
+    SurfaceState(SurfaceState&& other);
+    SurfaceState& operator=(SurfaceState&& other);
+
+    int z_order = 0;
+    gfx::OverlayTransform transform = gfx::OVERLAY_TRANSFORM_INVALID;
+    base::android::ScopedHardwareBufferHandle hardware_buffer;
+    gfx::Rect bounds_rect;
+    gfx::Rect crop_rect;
+    bool opaque = true;
+
+    gl::SurfaceComposer::Surface surface;
+  };
+
+  // Holds the surface state changes made since the last call to SwapBuffers.
+  base::Optional<gl::SurfaceComposer::Transaction> pending_transaction_;
+
+  // The list of Surfaces and the corresponding state. The initial
+  // |pending_surfaces_count_| surfaces in this list are surfaces with state
+  // mutated since the last SwapBuffers with the updates collected in
+  // |pending_transaction_|.
+  // On the next SwapBuffers, the updates in the transaction are applied
+  // atomically and any surfaces in |surface_list_| which are not reused in this
+  // frame are destroyed.
+  std::vector<SurfaceState> surface_list_;
+  size_t pending_surfaces_count_ = 0u;
+
+  std::unique_ptr<gl::SurfaceComposer> surface_composer_;
+};
+
+}  // namespace gl
+
+#endif  // UI_GL_GL_SURFACE_EGL_SURFACE_CONTROL_H_
diff --git a/ui/gl/test/gl_image_test_support.cc b/ui/gl/test/gl_image_test_support.cc
index dafae4e..659cedf 100644
--- a/ui/gl/test/gl_image_test_support.cc
+++ b/ui/gl/test/gl_image_test_support.cc
@@ -226,11 +226,6 @@
       }
       return;
     }
-    case gfx::BufferFormat::ATC:
-    case gfx::BufferFormat::ATCIA:
-    case gfx::BufferFormat::DXT1:
-    case gfx::BufferFormat::DXT5:
-    case gfx::BufferFormat::ETC1:
     case gfx::BufferFormat::RGBA_4444:
     case gfx::BufferFormat::UYVY_422:
       NOTREACHED() << gfx::BufferFormatToString(format);
diff --git a/ui/views/accessibility/ax_window_obj_wrapper.cc b/ui/views/accessibility/ax_window_obj_wrapper.cc
index d33524c..cd77dabf 100644
--- a/ui/views/accessibility/ax_window_obj_wrapper.cc
+++ b/ui/views/accessibility/ax_window_obj_wrapper.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/accessibility/ax_tree_id.h"
 #include "ui/accessibility/platform/aura_window_properties.h"
 #include "ui/accessibility/platform/ax_unique_id.h"
 #include "ui/aura/client/focus_client.h"
@@ -96,8 +97,9 @@
   if (!window_->IsVisible())
     out_node_data->AddState(ax::mojom::State::kInvisible);
   out_node_data->location = gfx::RectF(window_->GetBoundsInScreen());
-  ui::AXTreeID* child_ax_tree_id_ptr = window_->GetProperty(ui::kChildAXTreeID);
-  if (child_ax_tree_id_ptr && *child_ax_tree_id_ptr != ui::AXTreeIDUnknown()) {
+  std::string* child_ax_tree_id_ptr = window_->GetProperty(ui::kChildAXTreeID);
+  if (child_ax_tree_id_ptr && ui::AXTreeID::FromString(*child_ax_tree_id_ptr) !=
+                                  ui::AXTreeIDUnknown()) {
     // Most often, child AX trees are parented to Views. We need to handle
     // the case where they're not here, but we don't want the same AX tree
     // to be a child of two different parents.
diff --git a/ui/views/cocoa/bridge_factory_host.cc b/ui/views/cocoa/bridge_factory_host.cc
index a660a20b..4350aae5 100644
--- a/ui/views/cocoa/bridge_factory_host.cc
+++ b/ui/views/cocoa/bridge_factory_host.cc
@@ -8,14 +8,10 @@
 
 namespace views {
 
-namespace {
-// Start the ids at something far from zero to help in debugging.
-uint64_t g_next_bridge_factory_host_id_ = 0x1000;
-}  // namespace
-
 BridgeFactoryHost::BridgeFactoryHost(
-    views_bridge_mac::mojom::BridgeFactoryRequest* request)
-    : host_id_(g_next_bridge_factory_host_id_++) {
+    uint64_t host_id,
+    views_bridge_mac::mojom::BridgeFactoryAssociatedRequest* request)
+    : host_id_(host_id) {
   *request = mojo::MakeRequest(&bridge_factory_ptr_);
 }
 
diff --git a/ui/views/cocoa/bridge_factory_host.h b/ui/views/cocoa/bridge_factory_host.h
index e8027a4..14a197d 100644
--- a/ui/views/cocoa/bridge_factory_host.h
+++ b/ui/views/cocoa/bridge_factory_host.h
@@ -22,7 +22,9 @@
     ~Observer() override {}
   };
 
-  BridgeFactoryHost(views_bridge_mac::mojom::BridgeFactoryRequest* request);
+  BridgeFactoryHost(
+      uint64_t host_id,
+      views_bridge_mac::mojom::BridgeFactoryAssociatedRequest* request);
   ~BridgeFactoryHost();
 
   // Return an id for the host process. This can be used to look up other
@@ -36,7 +38,7 @@
 
  private:
   const uint64_t host_id_;
-  views_bridge_mac::mojom::BridgeFactoryPtr bridge_factory_ptr_;
+  views_bridge_mac::mojom::BridgeFactoryAssociatedPtr bridge_factory_ptr_;
   base::ObserverList<Observer> observers_;
 };
 
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.h b/ui/views/cocoa/bridged_native_widget_host_impl.h
index 4a6e120..fdfac6e 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.h
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.h
@@ -9,7 +9,7 @@
 
 #include "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 #include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
 #include "ui/accelerated_widget_mac/display_link_mac.h"
 #include "ui/base/ime/input_method_delegate.h"
@@ -312,7 +312,7 @@
 
   // The mojo pointer to a BridgedNativeWidget, which may exist in another
   // process.
-  views_bridge_mac::mojom::BridgedNativeWidgetPtr bridge_ptr_;
+  views_bridge_mac::mojom::BridgedNativeWidgetAssociatedPtr bridge_ptr_;
 
   // TODO(ccameron): Rather than instantiate a BridgedNativeWidgetImpl here,
   // we will instantiate a mojo BridgedNativeWidgetImpl interface to a Cocoa
@@ -353,7 +353,7 @@
   // Contains NativeViewHost->gfx::NativeView associations.
   std::map<const views::View*, NSView*> associated_views_;
 
-  mojo::Binding<views_bridge_mac::mojom::BridgedNativeWidgetHost>
+  mojo::AssociatedBinding<views_bridge_mac::mojom::BridgedNativeWidgetHost>
       host_mojo_binding_;
   DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetHostImpl);
 };
diff --git a/ui/views/cocoa/bridged_native_widget_host_impl.mm b/ui/views/cocoa/bridged_native_widget_host_impl.mm
index 0f669a0..7abdf47b 100644
--- a/ui/views/cocoa/bridged_native_widget_host_impl.mm
+++ b/ui/views/cocoa/bridged_native_widget_host_impl.mm
@@ -89,7 +89,8 @@
 
 BridgedNativeWidgetHostImpl::~BridgedNativeWidgetHostImpl() {
   if (bridge_factory_host_) {
-    bridge_factory_host_->GetFactory()->DestroyBridge(widget_id_);
+    bridge_ptr_.reset();
+    host_mojo_binding_.Unbind();
     bridge_factory_host_->RemoveObserver(this);
     bridge_factory_host_ = nullptr;
   }
@@ -147,11 +148,11 @@
   [local_window_ setBridgedNativeWidgetId:widget_id_];
 
   // Initialize |bridge_ptr_| to point to a bridge created by |factory|.
-  views_bridge_mac::mojom::BridgedNativeWidgetHostPtr host_ptr;
+  views_bridge_mac::mojom::BridgedNativeWidgetHostAssociatedPtr host_ptr;
   host_mojo_binding_.Bind(mojo::MakeRequest(&host_ptr),
                           ui::WindowResizeHelperMac::Get()->task_runner());
-  bridge_factory_host_->GetFactory()->CreateBridge(
-      widget_id_, mojo::MakeRequest(&bridge_ptr_), std::move(host_ptr));
+  bridge_factory_host_->GetFactory()->CreateBridgedNativeWidget(
+      widget_id_, mojo::MakeRequest(&bridge_ptr_), host_ptr.PassInterface());
 
   // Create the window in its process, and attach it to its parent window.
   bridge()->CreateWindow(std::move(window_create_params), parent_bridge_id);
diff --git a/ui/views/mus/ax_remote_host.cc b/ui/views/mus/ax_remote_host.cc
index ff18dd8..d0f40dc 100644
--- a/ui/views/mus/ax_remote_host.cc
+++ b/ui/views/mus/ax_remote_host.cc
@@ -11,6 +11,7 @@
 #include "ui/accessibility/ax_action_data.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_event.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
 #include "ui/accessibility/platform/ax_unique_id.h"
 #include "ui/aura/mus/window_tree_client.h"
 #include "ui/aura/window.h"
@@ -60,6 +61,10 @@
   widget_ = widget;
   widget_->AddObserver(this);
 
+  DCHECK_NE(tree_id_, ui::AXTreeIDUnknown());
+  widget_->GetNativeWindow()->SetProperty(ui::kChildAXTreeID,
+                                          new std::string(tree_id_.ToString()));
+
   // The cache needs to track the root window to follow focus changes.
   AXAuraObjCache* cache = AXAuraObjCache::GetInstance();
   cache->OnRootWindowObjCreated(widget_->GetNativeWindow());
@@ -190,7 +195,7 @@
 
 void AXRemoteHost::Enable() {
   // Don't early-exit if already enabled. AXRemoteHost can start up in the
-  // "enabled" state even if ChromeVox is on at the moment the app launches.
+  // "enabled" state even if ChromeVox is off at the moment the app launches.
   // Turning on ChromeVox later will generate another OnAutomationEnabled()
   // call and we need to serialize the node tree again. This is similar to
   // AutomationManagerAura's behavior. https://crbug.com/876407
diff --git a/ui/views/mus/ax_remote_host_unittest.cc b/ui/views/mus/ax_remote_host_unittest.cc
index 0ed0034..80908fc2 100644
--- a/ui/views/mus/ax_remote_host_unittest.cc
+++ b/ui/views/mus/ax_remote_host_unittest.cc
@@ -5,9 +5,11 @@
 #include "ui/views/mus/ax_remote_host.h"
 
 #include "base/macros.h"
+#include "base/no_destructor.h"
 #include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/accessibility/mojom/ax_host.mojom.h"
+#include "ui/accessibility/platform/aura_window_properties.h"
 #include "ui/display/display.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 #include "ui/gfx/transform.h"
@@ -21,6 +23,13 @@
 namespace views {
 namespace {
 
+// Returns a well-known tree ID for the test widget.
+const ui::AXTreeID& TestAXTreeID() {
+  static const base::NoDestructor<ui::AXTreeID> test_ax_tree_id(
+      ui::AXTreeID::FromString("123"));
+  return *test_ax_tree_id;
+}
+
 // Simulates the AXHostService in the browser.
 class TestAXHostService : public ax::mojom::AXHost {
  public:
@@ -46,8 +55,7 @@
   void SetRemoteHost(ax::mojom::AXRemoteHostPtr client,
                      SetRemoteHostCallback cb) override {
     ++add_client_count_;
-    const ui::AXTreeID tree_id = ui::AXTreeID::FromString("123");
-    std::move(cb).Run(tree_id, automation_enabled_);
+    std::move(cb).Run(TestAXTreeID(), automation_enabled_);
     client.FlushForTesting();
   }
   void HandleAccessibilityEvent(const ui::AXTreeID& tree_id,
@@ -138,7 +146,15 @@
   std::unique_ptr<Widget> widget = CreateTestWidget();
   remote->FlushForTesting();
 
+  // Tree ID is assigned.
+  std::string* tree_id_ptr =
+      widget->GetNativeWindow()->GetProperty(ui::kChildAXTreeID);
+  ASSERT_TRUE(tree_id_ptr);
+  ui::AXTreeID tree_id = ui::AXTreeID::FromString(*tree_id_ptr);
+  EXPECT_EQ(TestAXTreeID(), tree_id);
+
   // Event was sent with initial hierarchy.
+  EXPECT_EQ(TestAXTreeID(), service.last_tree_id_);
   EXPECT_EQ(ax::mojom::Event::kLoadComplete, service.last_event_.event_type);
   EXPECT_EQ(AXAuraObjCache::GetInstance()->GetID(
                 widget->widget_delegate()->GetContentsView()),
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
index 453b6a5..c372bd2 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc
@@ -1004,7 +1004,6 @@
   if (is_fullscreen_ == fullscreen)
     return;
   is_fullscreen_ = fullscreen;
-  OnFullscreenStateChanged();
   if (is_fullscreen_)
     delayed_resize_task_.Cancel();
 
@@ -1370,10 +1369,6 @@
   }
 }
 
-void DesktopWindowTreeHostX11::OnMaximizedStateChanged() {}
-
-void DesktopWindowTreeHostX11::OnFullscreenStateChanged() {}
-
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopWindowTreeHostX11, private:
 
@@ -1675,12 +1670,10 @@
 void DesktopWindowTreeHostX11::UpdateWindowProperties(
     const base::flat_set<XAtom>& new_window_properties) {
   bool was_minimized = IsMinimized();
-  bool was_maximized = IsMaximized();
 
   window_properties_ = new_window_properties;
 
   bool is_minimized = IsMinimized();
-  bool is_maximized = IsMaximized();
 
   // Propagate the window minimization information to the content window, so
   // the render side can update its visibility properly. OnWMStateUpdated() is
@@ -1727,9 +1720,6 @@
   is_always_on_top_ = ui::HasWMSpecProperty(
       window_properties_, gfx::GetAtom("_NET_WM_STATE_ABOVE"));
 
-  if (was_maximized != is_maximized)
-    OnMaximizedStateChanged();
-
   // Now that we have different window properties, we may need to relayout the
   // window. (The windows code doesn't need this because their window change is
   // synchronous.)
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
index cc9d5fb..4ae19b0 100644
--- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
+++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h
@@ -184,12 +184,6 @@
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics) override;
 
-  // Called after the window is maximized or restored.
-  virtual void OnMaximizedStateChanged();
-
-  // Called after the window is fullscreened or unfullscreened.
-  virtual void OnFullscreenStateChanged();
-
  private:
   friend class DesktopWindowTreeHostX11HighDPITest;
 
diff --git a/ui/views_bridge_mac/bridge_factory_impl.h b/ui/views_bridge_mac/bridge_factory_impl.h
index 197820e5..5075e76bf 100644
--- a/ui/views_bridge_mac/bridge_factory_impl.h
+++ b/ui/views_bridge_mac/bridge_factory_impl.h
@@ -5,7 +5,7 @@
 #ifndef UI_VIEWS_BRIDGE_MAC_BRIDGE_FACTORY_IMPL_H_
 #define UI_VIEWS_BRIDGE_MAC_BRIDGE_FACTORY_IMPL_H_
 
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 #include "ui/views/views_export.h"
 #include "ui/views_bridge_mac/mojo/bridge_factory.mojom.h"
 #include "ui/views_bridge_mac/mojo/bridged_native_widget.mojom.h"
@@ -20,20 +20,20 @@
 class VIEWS_EXPORT BridgeFactoryImpl : public mojom::BridgeFactory {
  public:
   static BridgeFactoryImpl* Get();
-  void BindRequest(mojom::BridgeFactoryRequest request);
+  void BindRequest(mojom::BridgeFactoryAssociatedRequest request);
 
   // mojom::BridgeFactory:
-  void CreateBridge(uint64_t bridge_id,
-                    mojom::BridgedNativeWidgetRequest bridge_request,
-                    mojom::BridgedNativeWidgetHostPtr host) override;
-  void DestroyBridge(uint64_t bridge_id) override;
+  void CreateBridgedNativeWidget(
+      uint64_t bridge_id,
+      mojom::BridgedNativeWidgetAssociatedRequest bridge_request,
+      mojom::BridgedNativeWidgetHostAssociatedPtrInfo host) override;
 
  private:
   friend class base::NoDestructor<BridgeFactoryImpl>;
   BridgeFactoryImpl();
   ~BridgeFactoryImpl() override;
 
-  mojo::Binding<mojom::BridgeFactory> binding_;
+  mojo::AssociatedBinding<mojom::BridgeFactory> binding_;
 };
 
 }  // namespace views_bridge_mac
diff --git a/ui/views_bridge_mac/bridge_factory_impl.mm b/ui/views_bridge_mac/bridge_factory_impl.mm
index 947249d..323abef 100644
--- a/ui/views_bridge_mac/bridge_factory_impl.mm
+++ b/ui/views_bridge_mac/bridge_factory_impl.mm
@@ -5,6 +5,7 @@
 #include "ui/views_bridge_mac/bridge_factory_impl.h"
 
 #include "base/no_destructor.h"
+#include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #include "ui/views_bridge_mac/bridged_native_widget_host_helper.h"
 #include "ui/views_bridge_mac/bridged_native_widget_impl.h"
 
@@ -18,15 +19,22 @@
 class Bridge : public BridgedNativeWidgetHostHelper {
  public:
   Bridge(uint64_t bridge_id,
-         mojom::BridgedNativeWidgetHostPtr host_ptr,
-         mojom::BridgedNativeWidgetRequest bridge_request) {
-    host_ptr_ = std::move(host_ptr);
+         mojom::BridgedNativeWidgetHostAssociatedPtrInfo host_ptr,
+         mojom::BridgedNativeWidgetAssociatedRequest bridge_request) {
+    host_ptr_.Bind(std::move(host_ptr),
+                   ui::WindowResizeHelperMac::Get()->task_runner());
     bridge_impl_ = std::make_unique<BridgedNativeWidgetImpl>(
         bridge_id, host_ptr_.get(), this);
-    bridge_impl_->BindRequest(std::move(bridge_request));
+    bridge_impl_->BindRequest(
+        std::move(bridge_request),
+        base::BindOnce(&Bridge::OnConnectionError, base::Unretained(this)));
   }
+
+ private:
   ~Bridge() override {}
 
+  void OnConnectionError() { delete this; }
+
   // BridgedNativeWidgetHostHelper:
   NSView* GetNativeViewAccessible() override { return nil; }
   void DispatchKeyEvent(ui::KeyEvent* event) override {}
@@ -45,15 +53,10 @@
     return nullptr;
   }
 
-  mojom::BridgedNativeWidgetHostPtr host_ptr_;
+  mojom::BridgedNativeWidgetHostAssociatedPtr host_ptr_;
   std::unique_ptr<BridgedNativeWidgetImpl> bridge_impl_;
 };
 
-std::map<uint64_t, std::unique_ptr<Bridge>>& GetBridgeMap() {
-  static base::NoDestructor<std::map<uint64_t, std::unique_ptr<Bridge>>> map;
-  return *map;
-}
-
 }  // namespace
 
 // static
@@ -62,20 +65,18 @@
   return factory.get();
 }
 
-void BridgeFactoryImpl::BindRequest(mojom::BridgeFactoryRequest request) {
+void BridgeFactoryImpl::BindRequest(
+    mojom::BridgeFactoryAssociatedRequest request) {
   binding_.Bind(std::move(request));
 }
 
-void BridgeFactoryImpl::CreateBridge(
+void BridgeFactoryImpl::CreateBridgedNativeWidget(
     uint64_t bridge_id,
-    mojom::BridgedNativeWidgetRequest bridge_request,
-    mojom::BridgedNativeWidgetHostPtr host_ptr) {
-  GetBridgeMap()[bridge_id] = std::make_unique<Bridge>(
-      bridge_id, std::move(host_ptr), std::move(bridge_request));
-}
-
-void BridgeFactoryImpl::DestroyBridge(uint64_t bridge_id) {
-  GetBridgeMap().erase(bridge_id);
+    mojom::BridgedNativeWidgetAssociatedRequest bridge_request,
+    mojom::BridgedNativeWidgetHostAssociatedPtrInfo host) {
+  // The resulting object will be destroyed when its message pipe is closed.
+  ignore_result(
+      new Bridge(bridge_id, std::move(host), std::move(bridge_request)));
 }
 
 BridgeFactoryImpl::BridgeFactoryImpl() : binding_(this) {}
diff --git a/ui/views_bridge_mac/bridged_native_widget_impl.h b/ui/views_bridge_mac/bridged_native_widget_impl.h
index 218b242..a711657 100644
--- a/ui/views_bridge_mac/bridged_native_widget_impl.h
+++ b/ui/views_bridge_mac/bridged_native_widget_impl.h
@@ -13,7 +13,7 @@
 #import "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
 #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
-#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
 #include "ui/accelerated_widget_mac/ca_transaction_observer.h"
 #include "ui/accelerated_widget_mac/display_ca_layer_tree.h"
 #include "ui/base/cocoa/ns_view_ids.h"
@@ -84,7 +84,13 @@
                           BridgedNativeWidgetHost* host,
                           BridgedNativeWidgetHostHelper* host_helper);
   ~BridgedNativeWidgetImpl() override;
-  void BindRequest(views_bridge_mac::mojom::BridgedNativeWidgetRequest request);
+
+  // Bind |bridge_mojo_binding_| to |request|, and set the connection error
+  // callback for |bridge_mojo_binding_| to |connection_closed_callback| (which
+  // will delete |this| when the connection is closed).
+  void BindRequest(
+      views_bridge_mac::mojom::BridgedNativeWidgetAssociatedRequest request,
+      base::OnceClosure connection_closed_callback);
 
   // Initialize the NSWindow by taking ownership of the specified object.
   // TODO(ccameron): When a BridgedNativeWidgetImpl is allocated across a
@@ -341,7 +347,7 @@
   // shadow needs to be invalidated when a frame is received for the new shape.
   bool invalidate_shadow_on_frame_swap_ = false;
 
-  mojo::Binding<views_bridge_mac::mojom::BridgedNativeWidget>
+  mojo::AssociatedBinding<views_bridge_mac::mojom::BridgedNativeWidget>
       bridge_mojo_binding_;
   DISALLOW_COPY_AND_ASSIGN(BridgedNativeWidgetImpl);
 };
diff --git a/ui/views_bridge_mac/bridged_native_widget_impl.mm b/ui/views_bridge_mac/bridged_native_widget_impl.mm
index 6bc4c62..d1a34f1 100644
--- a/ui/views_bridge_mac/bridged_native_widget_impl.mm
+++ b/ui/views_bridge_mac/bridged_native_widget_impl.mm
@@ -282,9 +282,12 @@
 }
 
 void BridgedNativeWidgetImpl::BindRequest(
-    views_bridge_mac::mojom::BridgedNativeWidgetRequest request) {
+    views_bridge_mac::mojom::BridgedNativeWidgetAssociatedRequest request,
+    base::OnceClosure connection_closed_callback) {
   bridge_mojo_binding_.Bind(std::move(request),
                             ui::WindowResizeHelperMac::Get()->task_runner());
+  bridge_mojo_binding_.set_connection_error_handler(
+      std::move(connection_closed_callback));
 }
 
 void BridgedNativeWidgetImpl::SetWindow(
diff --git a/ui/views_bridge_mac/mojo/bridge_factory.mojom b/ui/views_bridge_mac/mojo/bridge_factory.mojom
index e9e5f54..246ba5bb 100644
--- a/ui/views_bridge_mac/mojo/bridge_factory.mojom
+++ b/ui/views_bridge_mac/mojo/bridge_factory.mojom
@@ -9,10 +9,12 @@
 
 // The interface through which a bridge is created and connected to its host.
 interface BridgeFactory {
-  CreateBridge(
+  // Create a bridge for a native widget. The resulting object will be owned by
+  // the connection for |host|. Closing that connection will result in deleting
+  // the bridge.
+  CreateBridgedNativeWidget(
       uint64 bridge_id,
-      BridgedNativeWidget& bridge_request,
-      BridgedNativeWidgetHost host);
-  DestroyBridge(uint64 bridge_id);
+      associated BridgedNativeWidget& bridge_request,
+      associated BridgedNativeWidgetHost host);
 };