diff --git a/DEPS b/DEPS
index 3b5cd12..211d474f 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '0098ccbab5d10040f021daab5bff7a38e718a309',
+  'skia_revision': 'd37570b325e2a8c78aa232d13e502c8d24de7d46',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '8aa858e5115a8cdb376deb0c42561dea10c5d32a',
+  'v8_revision': 'c5a1fcbf544dc5ca5d901e96e2228d1eb767251b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -117,7 +117,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': '4ebd8f3d9999ca4cd1ec769fe4c4aaa2fceda431',
+  'angle_revision': 'b36a4816a5460120249e89258af3c5741301de40',
   # 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.
@@ -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': '90a12b3d4d1d589b3d61c194f983eb9c22459226',
+  'spv_tools_revision': '903514f95445267754e28f0cd8def22e9533ebe8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -313,7 +313,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + '827c67034ba293e6e4676689979571e471ec5486',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'a9d14ef965d6e5e4852998b17a283e560990206e',
       'condition': 'checkout_ios',
   },
 
@@ -954,7 +954,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'd963884232959c2de9b7b149530cbfea26fad6dc',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '2e5a2964784b33df48a0ad0827ed105e4fecfe3d',
 
   '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' + '@' + 'bacfd87b3be2a9d211560994b4e276a882188834',
+    Var('webrtc_git') + '/src.git' + '@' + 'a7af0218826cfed77664e6723470c77089e12db1',
 
   '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@d6b25c280cdc9cddda34ce091857f0fa6dd1cc83',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@be0a57bc9068ed15b2c91555ab9c5622baf18a36',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/app_list/views/folder_header_view.cc b/ash/app_list/views/folder_header_view.cc
index ef3aa40..fa92920 100644
--- a/ash/app_list/views/folder_header_view.cc
+++ b/ash/app_list/views/folder_header_view.cc
@@ -201,7 +201,10 @@
       folder_name_view_->GetInsets().width();
   text_width = std::min(text_width, GetMaxFolderNameWidth());
   text_bounds.set_x(rect.x() + (rect.width() - text_width) / 2);
-  text_bounds.set_width(text_width);
+
+  // The width of the text field should always be maximum length, to prevent the
+  // touch target from resizing with the text.
+  text_bounds.set_width(GetMaxFolderNameWidth());
   text_bounds.ClampToCenteredSize(gfx::Size(
       text_bounds.width(), folder_name_view_->GetPreferredSize().height()));
   folder_name_view_->SetBoundsRect(text_bounds);
diff --git a/ash/app_list/views/folder_header_view.h b/ash/app_list/views/folder_header_view.h
index 65e92980..082726e 100644
--- a/ash/app_list/views/folder_header_view.h
+++ b/ash/app_list/views/folder_header_view.h
@@ -23,7 +23,7 @@
 class FolderHeaderViewTest;
 }
 
-// FolderHeaderView contains a back button and an editable folder name field.
+// FolderHeaderView contains an editable folder name field.
 class APP_LIST_EXPORT FolderHeaderView : public views::View,
                                          public views::TextfieldController,
                                          public AppListItemObserver {
diff --git a/ash/assistant/assistant_interaction_controller.cc b/ash/assistant/assistant_interaction_controller.cc
index 57ff8892a3..a4017ee 100644
--- a/ash/assistant/assistant_interaction_controller.cc
+++ b/ash/assistant/assistant_interaction_controller.cc
@@ -162,11 +162,10 @@
       model_.SetInputModality(InputModality::kKeyboard);
       break;
     case AssistantVisibility::kVisible:
-      if (source == AssistantSource::kLauncherSearchBox) {
+      if (source == AssistantSource::kLauncherSearchBox ||
+          source == AssistantSource::kLongPressLauncher) {
         if (IsTabletMode())
           StartVoiceInteraction();
-      } else if (source == AssistantSource::kLongPressLauncher) {
-        StartVoiceInteraction();
       } else if (source == AssistantSource::kStylus) {
         model_.SetInputModality(InputModality::kStylus);
       }
diff --git a/base/allocator/partition_allocator/partition_alloc.h b/base/allocator/partition_allocator/partition_alloc.h
index 9455fe3c..95611a5 100644
--- a/base/allocator/partition_allocator/partition_alloc.h
+++ b/base/allocator/partition_allocator/partition_alloc.h
@@ -337,6 +337,7 @@
   internal::PartitionBucket* bucket =
       root->bucket_lookups[(order << kGenericNumBucketsPerOrderBits) +
                            order_index + !!sub_order_index];
+  CHECK(bucket);
   DCHECK(!bucket->slot_size || bucket->slot_size >= size);
   DCHECK(!(bucket->slot_size % kGenericSmallestBucket));
   return bucket;
diff --git a/base/memory/platform_shared_memory_region_android.cc b/base/memory/platform_shared_memory_region_android.cc
index a529725..c7dd5a9 100644
--- a/base/memory/platform_shared_memory_region_android.cc
+++ b/base/memory/platform_shared_memory_region_android.cc
@@ -6,8 +6,10 @@
 
 #include <sys/mman.h>
 
+#include "base/bits.h"
 #include "base/memory/shared_memory_tracker.h"
 #include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
 #include "third_party/ashmem/ashmem.h"
 
 namespace base {
@@ -159,7 +161,9 @@
   if (size == 0)
     return {};
 
-  if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
+  // Align size as required by ashmem_create_region() API documentation.
+  size_t rounded_size = bits::Align(size, GetPageSize());
+  if (rounded_size > static_cast<size_t>(std::numeric_limits<int>::max()))
     return {};
 
   CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
@@ -168,7 +172,7 @@
   UnguessableToken guid = UnguessableToken::Create();
 
   ScopedFD fd(ashmem_create_region(
-      SharedMemoryTracker::GetDumpNameForTracing(guid).c_str(), size));
+      SharedMemoryTracker::GetDumpNameForTracing(guid).c_str(), rounded_size));
   if (!fd.is_valid()) {
     DPLOG(ERROR) << "ashmem_create_region failed";
     return {};
diff --git a/base/memory/shared_memory_android.cc b/base/memory/shared_memory_android.cc
index c126767..e54e61a 100644
--- a/base/memory/shared_memory_android.cc
+++ b/base/memory/shared_memory_android.cc
@@ -7,7 +7,9 @@
 #include <stddef.h>
 #include <sys/mman.h>
 
+#include "base/bits.h"
 #include "base/logging.h"
+#include "base/process/process_metrics.h"
 #include "third_party/ashmem/ashmem.h"
 
 namespace base {
@@ -20,13 +22,16 @@
 bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
   DCHECK(!shm_.IsValid());
 
-  if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
+  // Align size as required by ashmem_create_region() API documentation.
+  size_t rounded_size = bits::Align(options.size, GetPageSize());
+
+  if (rounded_size > static_cast<size_t>(std::numeric_limits<int>::max()))
     return false;
 
   // "name" is just a label in ashmem. It is visible in /proc/pid/maps.
   int fd = ashmem_create_region(
       options.name_deprecated ? options.name_deprecated->c_str() : "",
-      options.size);
+      rounded_size);
   shm_ = SharedMemoryHandle::ImportHandle(fd, options.size);
   if (!shm_.IsValid()) {
     DLOG(ERROR) << "Shared memory creation failed";
diff --git a/base/threading/scoped_blocking_call.h b/base/threading/scoped_blocking_call.h
index 144480b9..516ac0a 100644
--- a/base/threading/scoped_blocking_call.h
+++ b/base/threading/scoped_blocking_call.h
@@ -10,6 +10,12 @@
 
 namespace base {
 
+// A "blocking call" refers to any call that causes the calling thread to wait
+// off-CPU. It includes but is not limited to calls that wait on synchronous
+// file I/O operations: read or write a file from disk, interact with a pipe or
+// a socket, rename or delete a file, enumerate files in a directory, etc.
+// Acquiring a low contention lock is not considered a blocking call.
+
 // BlockingType indicates the likelihood that a blocking call will actually
 // block.
 enum class BlockingType {
@@ -46,14 +52,16 @@
 
 }  // namespace internal
 
-// This class must be instantiated in every scope where a blocking call is made.
-// When a ScopedBlockingCall is instantiated, it asserts that blocking calls are
-// allowed in its scope with a call to base::AssertBlockingAllowed(). CPU usage
-// should be minimal within that scope. //base APIs that block instantiate their
-// own ScopedBlockingCall; it is not necessary to instantiate another
-// ScopedBlockingCall in the scope where these APIs are used. Nested
-// ScopedBlockingCalls are supported (mostly a no-op except for WILL_BLOCK
-// nested within MAY_BLOCK which will result in immediate WILL_BLOCK semantics).
+// This class must be instantiated in every scope where a blocking call is made
+// and serves as a precise annotation of the scope that may/will block for the
+// scheduler. When a ScopedBlockingCall is instantiated, it asserts that
+// blocking calls are allowed in its scope with a call to
+// base::AssertBlockingAllowed(). CPU usage should be minimal within that scope.
+// //base APIs that block instantiate their own ScopedBlockingCall; it is not
+// necessary to instantiate another ScopedBlockingCall in the scope where these
+// APIs are used. Nested ScopedBlockingCalls are supported (mostly a no-op
+// except for WILL_BLOCK nested within MAY_BLOCK which will result in immediate
+// WILL_BLOCK semantics).
 //
 // Good:
 //   Data data;
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 844dc792..b5a24d0 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -376,7 +376,7 @@
   defines = [ "CC_IMPLEMENTATION=1" ]
 }
 
-cc_static_library("test_support") {
+cc_test_static_library("test_support") {
   testonly = true
   sources = [
     "test/animation_test_common.cc",
diff --git a/cc/cc.gni b/cc/cc.gni
index 44a5eebc5..51bbd51a 100644
--- a/cc/cc.gni
+++ b/cc/cc.gni
@@ -6,24 +6,16 @@
 import("//testing/test.gni")
 
 cc_remove_configs = []
-cc_add_configs = [ "//build/config:precompiled_headers" ]
+cc_add_configs = [
+  "//build/config:precompiled_headers",
+  "//build/config/compiler:wexit_time_destructors",
+]
 
 if (!is_debug && (is_win || is_android)) {
   cc_remove_configs += [ "//build/config/compiler:default_optimization" ]
   cc_add_configs += [ "//build/config/compiler:optimize_max" ]
 }
 
-template("cc_source_set") {
-  jumbo_source_set(target_name) {
-    forward_variables_from(invoker, "*", [ "configs" ])
-    if (defined(invoker.configs)) {
-      configs += invoker.configs
-    }
-    configs -= cc_remove_configs
-    configs += cc_add_configs
-  }
-}
-
 template("cc_component") {
   jumbo_component(target_name) {
     forward_variables_from(invoker, "*", [ "configs" ])
@@ -35,7 +27,7 @@
   }
 }
 
-template("cc_static_library") {
+template("cc_test_static_library") {
   jumbo_static_library(target_name) {
     forward_variables_from(invoker, "*", [ "configs" ])
     if (defined(invoker.configs)) {
@@ -43,6 +35,9 @@
     }
     configs -= cc_remove_configs
     configs += cc_add_configs
+
+    # Not needed in test code.
+    configs -= [ "//build/config/compiler:wexit_time_destructors" ]
   }
 }
 
@@ -54,5 +49,8 @@
     }
     configs -= cc_remove_configs
     configs += cc_add_configs
+
+    # Not needed in test code.
+    configs -= [ "//build/config/compiler:wexit_time_destructors" ]
   }
 }
diff --git a/cc/input/main_thread_scrolling_reason.cc b/cc/input/main_thread_scrolling_reason.cc
index 6653ac9..a85b60f 100644
--- a/cc/input/main_thread_scrolling_reason.cc
+++ b/cc/input/main_thread_scrolling_reason.cc
@@ -71,6 +71,10 @@
     traced_value.AppendString("Non-invertible transform");
   if (reasons & kPageBasedScrolling)
     traced_value.AppendString("Page-based scrolling");
+  if (reasons & kWheelEventHandlerRegion)
+    traced_value.AppendString("Wheel event handler region");
+  if (reasons & kTouchEventHandlerRegion)
+    traced_value.AppendString("Touch event handler region");
 
   traced_value.EndArray();
 }
diff --git a/cc/input/main_thread_scrolling_reason.h b/cc/input/main_thread_scrolling_reason.h
index b926c751..cf2deff 100644
--- a/cc/input/main_thread_scrolling_reason.h
+++ b/cc/input/main_thread_scrolling_reason.h
@@ -60,12 +60,14 @@
     kContinuingMainThreadScroll = 1 << 10,
     kNonInvertibleTransform = 1 << 11,
     kPageBasedScrolling = 1 << 12,
+    kWheelEventHandlerRegion = 1 << 23,
+    kTouchEventHandlerRegion = 1 << 24,
 
     // The maximum number of flags in this struct (excluding itself).
     // New flags should increment this number but it should never be decremented
     // because the values are used in UMA histograms. It should also be noted
     // that it excludes the kNotScrollingOnMain value.
-    kMainThreadScrollingReasonCount = 23,
+    kMainThreadScrollingReasonCount = 25,
   };
 
   static const uint32_t kNonCompositedReasons =
@@ -91,7 +93,8 @@
     uint32_t reasons_set_by_compositor =
         kNonFastScrollableRegion | kFailedHitTest | kNoScrollingLayer |
         kNotScrollable | kContinuingMainThreadScroll | kNonInvertibleTransform |
-        kPageBasedScrolling;
+        kPageBasedScrolling | kWheelEventHandlerRegion |
+        kTouchEventHandlerRegion;
     return (reasons & reasons_set_by_compositor) == reasons;
   }
 
diff --git a/cc/input/main_thread_scrolling_reason_unittest.cc b/cc/input/main_thread_scrolling_reason_unittest.cc
index ec49ff9..9f8e6b6 100644
--- a/cc/input/main_thread_scrolling_reason_unittest.cc
+++ b/cc/input/main_thread_scrolling_reason_unittest.cc
@@ -31,7 +31,9 @@
       "Not scrollable,"
       "Continuing main thread scroll,"
       "Non-invertible transform,"
-      "Page-based scrolling",
+      "Page-based scrolling,"
+      "Wheel event handler region,"
+      "Touch event handler region",
       MainThreadScrollingReason::AsText(0xffffffffu));
 }
 
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index d28e609..9b7809e3 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -13,6 +13,7 @@
 #include <set>
 
 #include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "build/build_config.h"
@@ -666,11 +667,11 @@
         !layer_tree_impl()->SmoothnessTakesPriority();
   }
 
-  static const Occlusion kEmptyOcclusion;
+  static const base::NoDestructor<Occlusion> kEmptyOcclusion;
   const Occlusion& occlusion_in_content_space =
       layer_tree_impl()->settings().use_occlusion_for_tile_prioritization
           ? draw_properties().occlusion_in_content_space
-          : kEmptyOcclusion;
+          : *kEmptyOcclusion;
 
   // Pass |occlusion_in_content_space| for |occlusion_in_layer_space| since
   // they are the same space in picture layer, as contents scale is always 1.
diff --git a/cc/paint/discardable_image_map.cc b/cc/paint/discardable_image_map.cc
index 232dab6a..1c53bb9 100644
--- a/cc/paint/discardable_image_map.cc
+++ b/cc/paint/discardable_image_map.cc
@@ -12,6 +12,7 @@
 #include "base/auto_reset.h"
 #include "base/containers/adapters.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/paint/paint_filter.h"
 #include "cc/paint/paint_op_buffer.h"
@@ -456,9 +457,9 @@
 
 const DiscardableImageMap::Rects& DiscardableImageMap::GetRectsForImage(
     PaintImage::Id image_id) const {
-  static const Rects kEmptyRects;
+  static const base::NoDestructor<Rects> kEmptyRects;
   auto it = image_id_to_rects_.find(image_id);
-  return it == image_id_to_rects_.end() ? kEmptyRects : it->second;
+  return it == image_id_to_rects_.end() ? *kEmptyRects : it->second;
 }
 
 void DiscardableImageMap::Reset() {
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 93fbeb84..e53875b 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1958,6 +1958,11 @@
 
   metadata.min_page_scale_factor = active_tree_->min_page_scale_factor();
 
+  metadata.top_controls_height =
+      browser_controls_offset_manager_->TopControlsHeight();
+  metadata.top_controls_shown_ratio =
+      browser_controls_offset_manager_->TopControlsShownRatio();
+
 #if defined(OS_ANDROID)
   metadata.max_page_scale_factor = active_tree_->max_page_scale_factor();
   metadata.root_layer_size = active_tree_->ScrollableSize();
@@ -1967,10 +1972,6 @@
         !outer_viewport_scroll_node->user_scrollable_vertical;
   }
 
-  metadata.top_controls_height =
-      browser_controls_offset_manager_->TopControlsHeight();
-  metadata.top_controls_shown_ratio =
-      browser_controls_offset_manager_->TopControlsShownRatio();
   metadata.bottom_controls_height =
       browser_controls_offset_manager_->BottomControlsHeight();
   metadata.bottom_controls_shown_ratio =
diff --git a/cc/trees/render_frame_metadata.h b/cc/trees/render_frame_metadata.h
index bd261d6..8b6c45d 100644
--- a/cc/trees/render_frame_metadata.h
+++ b/cc/trees/render_frame_metadata.h
@@ -66,8 +66,8 @@
 
   float page_scale_factor = 1.f;
 
-  // Used to position the Android location top bar and page content, whose
-  // precise position is computed by the renderer compositor.
+  // Used to position the location top bar and page content, whose precise
+  // position is computed by the renderer compositor.
   float top_controls_height = 0.f;
   float top_controls_shown_ratio = 0.f;
 
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 85f66a45..e4aa553 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -391,6 +391,7 @@
     "//chrome/browser/android/crash/crash_keys_android.h",
     "//chrome/browser/android/customtabs/detached_resource_request.h",
     "//chrome/browser/android/digital_asset_links/digital_asset_links_handler.h",
+    "//chrome/browser/android/explore_sites/explore_sites_feature.h",
     "//chrome/browser/android/feedback/connectivity_checker.cc",
     "//chrome/browser/android/policy/policy_auditor.cc",
     "//chrome/browser/android/shortcut_info.h",
diff --git a/chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml b/chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml
index d456217..8ef6b6a 100644
--- a/chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml
+++ b/chrome/android/java/res/layout/experimental_explore_sites_category_tile_view.xml
@@ -15,7 +15,7 @@
 
     <!-- Main icon/image -->
     <ImageView
-        android:id="@+id/explore_sites_category_tile_icon"
+        android:id="@+id/experimental_explore_sites_category_tile_icon"
         android:layout_gravity="center_horizontal"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
@@ -23,7 +23,7 @@
 
     <!-- Category title -->
     <TextView
-        android:id="@+id/explore_sites_category_tile_title"
+        android:id="@+id/experimental_explore_sites_category_tile_title"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center_horizontal"
diff --git a/chrome/android/java/res/layout/experimental_explore_sites_section.xml b/chrome/android/java/res/layout/experimental_explore_sites_section.xml
index 9969ef2..76586bb 100644
--- a/chrome/android/java/res/layout/experimental_explore_sites_section.xml
+++ b/chrome/android/java/res/layout/experimental_explore_sites_section.xml
@@ -12,29 +12,29 @@
 
     <TextView
         style="@style/BlackCaption"
-        android:id="@+id/explore_sites_title"
+        android:id="@+id/experimental_explore_sites_title"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/explore_sites_spacing"
+        android:layout_marginTop="@dimen/experimental_explore_sites_spacing"
         android:gravity="center"
         android:text="@string/explore_sites_title" />
 
     <LinearLayout
-        android:id="@+id/explore_sites_tiles"
+        android:id="@+id/experimental_explore_sites_tiles"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/explore_sites_spacing"
-        android:paddingHorizontal="@dimen/explore_sites_padding"
+        android:layout_marginTop="@dimen/experimental_explore_sites_spacing"
+        android:paddingHorizontal="@dimen/experimental_explore_sites_padding"
         android:orientation="horizontal" />
 
     <Button
-        android:id="@+id/explore_sites_more_button"
+        android:id="@+id/experimental_explore_sites_more_button"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:gravity="center"
-        android:layout_marginTop="@dimen/explore_sites_spacing"
-        android:layout_marginHorizontal="@dimen/explore_sites_margin"
-        android:layout_marginBottom="@dimen/explore_sites_spacing"
+        android:layout_marginTop="@dimen/experimental_explore_sites_spacing"
+        android:layout_marginHorizontal="@dimen/experimental_explore_sites_margin"
+        android:layout_marginBottom="@dimen/experimental_explore_sites_spacing"
         android:text="@string/ntp_explore_sites_more" />
 
 </LinearLayout>
diff --git a/chrome/android/java/res/layout/explore_sites_category_tile_view.xml b/chrome/android/java/res/layout/explore_sites_category_tile_view.xml
new file mode 100644
index 0000000..258f178b
--- /dev/null
+++ b/chrome/android/java/res/layout/explore_sites_category_tile_view.xml
@@ -0,0 +1,18 @@
+<?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.explore_sites.ExploreSitesCategoryTileView
+    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="@dimen/tile_view_width"
+    android:layout_height="wrap_content"
+    android:paddingStart="@dimen/tile_view_padding"
+    android:paddingEnd="@dimen/tile_view_padding" >
+      <include
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        layout="@layout/tile_view_modern" />
+</org.chromium.chrome.browser.explore_sites.ExploreSitesCategoryTileView>
diff --git a/chrome/android/java/res/layout/explore_sites_category_tile_view_condensed.xml b/chrome/android/java/res/layout/explore_sites_category_tile_view_condensed.xml
new file mode 100644
index 0000000..86ad1c5
--- /dev/null
+++ b/chrome/android/java/res/layout/explore_sites_category_tile_view_condensed.xml
@@ -0,0 +1,18 @@
+<?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.explore_sites.ExploreSitesCategoryTileView
+    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="@dimen/tile_view_width_condensed"
+    android:layout_height="wrap_content"
+    android:paddingStart="@dimen/tile_view_padding"
+    android:paddingEnd="@dimen/tile_view_padding" >
+      <include
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        layout="@layout/tile_view_modern_condensed" />
+</org.chromium.chrome.browser.explore_sites.ExploreSitesCategoryTileView>
diff --git a/chrome/android/java/res/layout/explore_sites_section.xml b/chrome/android/java/res/layout/explore_sites_section.xml
new file mode 100644
index 0000000..f5f341e
--- /dev/null
+++ b/chrome/android/java/res/layout/explore_sites_section.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2018 The Chromium Authors. All rights reserved.
+     Use of this source code is governed by a BSD-style license that can be
+     found in the LICENSE file. -->
+
+<org.chromium.chrome.browser.suggestions.TileGridLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_gravity="top"
+    android:gravity="center_horizontal" />
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml
index 6a994f78..7c0158c 100644
--- a/chrome/android/java/res/layout/new_tab_page_layout.xml
+++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -85,7 +85,8 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:inflatedId="@+id/explore_sites"
-        android:layout="@layout/experimental_explore_sites_section" />
+        android:layout_marginBottom="16dp"
+        android:layout="@layout/explore_sites_section" />
 
     <!-- Site suggestion tile grid placeholder -->
     <ViewStub
diff --git a/chrome/android/java/res/layout/suggestions_tile_view.xml b/chrome/android/java/res/layout/suggestions_tile_view.xml
index e92c7dd..ba00700 100644
--- a/chrome/android/java/res/layout/suggestions_tile_view.xml
+++ b/chrome/android/java/res/layout/suggestions_tile_view.xml
@@ -10,8 +10,8 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="@dimen/tile_view_width"
     android:layout_height="wrap_content"
-    android:paddingStart="4dp"
-    android:paddingEnd="4dp" >
+    android:paddingStart="@dimen/tile_view_padding"
+    android:paddingEnd="@dimen/tile_view_padding" >
       <include
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/chrome/android/java/res/layout/suggestions_tile_view_condensed.xml b/chrome/android/java/res/layout/suggestions_tile_view_condensed.xml
index 2097270..820b0c5 100644
--- a/chrome/android/java/res/layout/suggestions_tile_view_condensed.xml
+++ b/chrome/android/java/res/layout/suggestions_tile_view_condensed.xml
@@ -10,8 +10,8 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="@dimen/tile_view_width_condensed"
     android:layout_height="wrap_content"
-    android:paddingStart="4dp"
-    android:paddingEnd="4dp" >
+    android:paddingStart="@dimen/tile_view_padding"
+    android:paddingEnd="@dimen/tile_view_padding" >
       <include
         android:layout_width="match_parent"
         android:layout_height="match_parent"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 15e2537..80d4f70 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -223,8 +223,6 @@
     <dimen name="control_container_height">56dp</dimen>
     <dimen name="bottom_toolbar_height">@dimen/min_touch_target_size</dimen>
     <dimen name="bottom_control_container_peek_height">48dp</dimen>
-    <dimen name="bottom_control_container_slim_peek_height">40dp</dimen>
-    <dimen name="bottom_control_container_slim_expanded_height">56dp</dimen>
     <dimen name="custom_tabs_control_container_height">56dp</dimen>
     <dimen name="fullscreen_activity_control_container_height">0dp</dimen>
 
@@ -315,15 +313,16 @@
     <dimen name="tile_view_offline_badge_margin_end_modern">9dp</dimen>
     <dimen name="tile_view_offline_badge_margin_top_modern_condensed">6dp</dimen>
     <dimen name="tile_view_offline_badge_margin_end_modern_condensed">7dp</dimen>
+    <dimen name="tile_view_padding">4dp</dimen>
     <dimen name="tile_view_title_margin_top_modern">61dp</dimen>
     <dimen name="ntp_logo_height">100dp</dimen>
     <dimen name="duet_ntp_logo_top_margin">-16dp</dimen>
     <dimen name="ntp_search_box_height">48dp</dimen>
     <dimen name="ntp_search_box_transition_length">16dp</dimen>
-    <dimen name="explore_sites_radius">8dp</dimen>
-    <dimen name="explore_sites_padding">8dp</dimen>
-    <dimen name="explore_sites_margin">16dp</dimen>
-    <dimen name="explore_sites_spacing">12dp</dimen>
+    <dimen name="experimental_explore_sites_radius">8dp</dimen>
+    <dimen name="experimental_explore_sites_padding">8dp</dimen>
+    <dimen name="experimental_explore_sites_margin">16dp</dimen>
+    <dimen name="experimental_explore_sites_spacing">12dp</dimen>
     <!-- Negative vertical inset added to the search box bounds when modern is enabled. 4dp is added
          to both the top and bottom bounds to bring the 48dp modern_toolbar_background_size to 56dp
          (matches toolbar_height_no_shadow). -->
diff --git a/chrome/android/java/res/xml/sync_and_services_preferences.xml b/chrome/android/java/res/xml/sync_and_services_preferences.xml
index 2205043..8b2cdc20 100644
--- a/chrome/android/java/res/xml/sync_and_services_preferences.xml
+++ b/chrome/android/java/res/xml/sync_and_services_preferences.xml
@@ -8,7 +8,7 @@
         android:key="sign_in"
         android:title="@string/sign_in_to_chrome"/>
 
-    <org.chromium.chrome.browser.preferences.SyncErrorCardPreference
+    <Preference
         android:key="sync_error_card"
         android:icon="@drawable/sync_error"
         android:title="@string/sync_error_card_title"/>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
index 4abdb98b..4cece6b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
@@ -296,7 +296,7 @@
     /**
      * @return The fullscreen width.
      */
-    private float getFullscreenWidth() {
+    public float getFullscreenWidth() {
         return mLayoutWidth;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
index 920bfa9..6e83f950 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
@@ -134,6 +134,7 @@
                 ContextualSearchPanel.CLOSE_ICON_DRAWABLE_ID, R.drawable.progress_bar_background,
                 R.drawable.progress_bar_foreground, searchPromoViewId,
                 R.drawable.contextual_search_promo_ripple, searchBarBannerTextViewId, mDpToPx,
+                panel.getFullscreenWidth() * mDpToPx, panel.getTabHeight() * mDpToPx,
                 panel.getBasePageBrightness(), panel.getBasePageY() * mDpToPx, panelWebContents,
                 searchPromoVisible, searchPromoHeightPx, searchPromoOpacity, searchBarBannerVisible,
                 searchBarBannerHeightPx, searchBarBannerPaddingPx, searchBarBannerRippleWidthPx,
@@ -203,14 +204,15 @@
             int searchProviderIconResourceId, int quickActionIconResourceId, int arrowUpResourceId,
             int closeIconResourceId, int progressBarBackgroundResourceId, int progressBarResourceId,
             int searchPromoResourceId, int barBannerRippleResourceId, int barBannerTextResourceId,
-            float dpToPx, float basePageBrightness, float basePageYOffset, WebContents webContents,
-            boolean searchPromoVisible, float searchPromoHeight, float searchPromoOpacity,
-            boolean searchBarBannerVisible, float searchBarBannerHeight,
-            float searchBarBannerPaddingPx, float searchBarBannerRippleWidth,
-            float searchBarBannerRippleOpacity, float searchBarBannerTextOpacity,
-            float searchPanelX, float searchPanelY, float searchPanelWidth, float searchPanelHeight,
-            float searchBarMarginSide, float searchBarHeight, float searchContextOpacity,
-            float searchTextLayerMinHeight, float searchTermOpacity, float searchTermCaptionSpacing,
+            float dpToPx, float layoutWidth, float layoutHeight, float basePageBrightness,
+            float basePageYOffset, WebContents webContents, boolean searchPromoVisible,
+            float searchPromoHeight, float searchPromoOpacity, boolean searchBarBannerVisible,
+            float searchBarBannerHeight, float searchBarBannerPaddingPx,
+            float searchBarBannerRippleWidth, float searchBarBannerRippleOpacity,
+            float searchBarBannerTextOpacity, float searchPanelX, float searchPanelY,
+            float searchPanelWidth, float searchPanelHeight, float searchBarMarginSide,
+            float searchBarHeight, float searchContextOpacity, float searchTextLayerMinHeight,
+            float searchTermOpacity, float searchTermCaptionSpacing,
             float searchCaptionAnimationPercentage, boolean searchCaptionVisible,
             boolean searchBarBorderVisible, float searchBarBorderHeight,
             boolean searchBarShadowVisible, float searchBarShadowOpacity,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java
index 41fa3ea4..c889edf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextual_suggestions/ContextualSuggestionsBottomSheetContent.java
@@ -62,11 +62,6 @@
     }
 
     @Override
-    public boolean useSlimPeek() {
-        return false;
-    }
-
-    @Override
     public int getSheetContentDescriptionStringId() {
         return R.string.contextual_suggestions_button_description;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
index 60bf266..3532786 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesCategoryTileView.java
@@ -45,17 +45,19 @@
     @Override
     public void onFinishInflate() {
         super.onFinishInflate();
-        mTitleView = findViewById(R.id.explore_sites_category_tile_title);
-        mIconView = findViewById(R.id.explore_sites_category_tile_icon);
+        mTitleView = findViewById(R.id.experimental_explore_sites_category_tile_title);
+        mIconView = findViewById(R.id.experimental_explore_sites_category_tile_icon);
     }
 
     public void initialize(ExploreSitesCategoryTile category, int widthPx) {
         mCategoryData = category;
-        mIconWidthPx =
-                widthPx - (2 * mResources.getDimensionPixelSize(R.dimen.explore_sites_padding));
+        mIconWidthPx = widthPx
+                - (2
+                          * mResources.getDimensionPixelSize(
+                                    R.dimen.experimental_explore_sites_padding));
         mIconHeightPx = mIconWidthPx * 2 / 3;
         mIconGenerator = new RoundedIconGenerator(mIconWidthPx, mIconHeightPx,
-                mResources.getDimensionPixelSize(R.dimen.explore_sites_radius),
+                mResources.getDimensionPixelSize(R.dimen.experimental_explore_sites_radius),
                 ApiCompatibilityUtils.getColor(
                         mResources, R.color.default_favicon_background_color),
                 mResources.getDimensionPixelSize(R.dimen.headline_size_medium));
@@ -71,7 +73,7 @@
         } else {
             drawable = ViewUtils.createRoundedBitmapDrawable(
                     Bitmap.createScaledBitmap(bitmap, mIconWidthPx, mIconHeightPx, false),
-                    mResources.getDimensionPixelSize(R.dimen.explore_sites_radius));
+                    mResources.getDimensionPixelSize(R.dimen.experimental_explore_sites_radius));
         }
         mCategoryData.setIconDrawable(drawable);
         mIconView.setImageDrawable(drawable);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
index 9969fc8..2afa2755 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
@@ -42,10 +42,11 @@
     }
 
     private void initialize() {
-        mCategorySection = mExploreSection.findViewById(R.id.explore_sites_tiles);
+        mCategorySection = mExploreSection.findViewById(R.id.experimental_explore_sites_tiles);
         ExploreSitesBridgeExperimental.getNtpCategories(mProfile, this::initializeTiles);
 
-        View moreCategoriesButton = mExploreSection.findViewById(R.id.explore_sites_more_button);
+        View moreCategoriesButton =
+                mExploreSection.findViewById(R.id.experimental_explore_sites_more_button);
         moreCategoriesButton.setOnClickListener(
                 (View v)
                         -> mNavigationDelegate.openUrl(WindowOpenDisposition.CURRENT_TAB,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
index b9eb85a..e98ed46 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
@@ -37,6 +37,15 @@
         finishedCallback.onResult(null);
     }
 
+    /**
+     * Gets the current Finch variation that is configured by flag or experiment.
+     */
+    @ExploreSitesVariation
+    public static int getVariation() {
+        return nativeGetVariation();
+    }
+
+    static native int nativeGetVariation();
     private static native void nativeGetEspCatalog(Profile profile,
             List<ExploreSitesCategory> result, Callback<List<ExploreSitesCategory>> callback);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategory.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategory.java
index b20322b..ad8f5c7c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategory.java
@@ -7,6 +7,7 @@
 import android.graphics.Bitmap;
 
 import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.browser.UrlConstants;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -53,6 +54,10 @@
         return mSites;
     }
 
+    public String getUrl() {
+        return UrlConstants.EXPLORE_URL + "#" + getId();
+    }
+
     // Creates a new category and appends to the given list. Also returns the created category to
     // easily append sites to the category.
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java
new file mode 100644
index 0000000..d38ccde
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java
@@ -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.
+
+package org.chromium.chrome.browser.explore_sites;
+
+import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
+import android.util.AttributeSet;
+
+import org.chromium.chrome.browser.ntp.TitleUtil;
+import org.chromium.chrome.browser.widget.tile.TileWithTextView;
+
+/**
+ * A category tile for ExploreSites, containing an icon that is a composition of sites' favicons
+ * within the category.  Alternatively, a MORE button.
+ */
+public class ExploreSitesCategoryTileView extends TileWithTextView {
+    private static final int TITLE_LINES = 1;
+    private static final boolean SUPPORTED_OFFLINE = false;
+
+    /** The data currently associated to this tile. */
+    private ExploreSitesCategory mCategory;
+
+    /**
+     * Constructor for inflating from XML.
+     */
+    public ExploreSitesCategoryTileView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    /**
+     * Initializes the view using the data held by {@code tile}. This should be called immediately
+     * after inflation.
+     * @param category The object that holds the data to populate this view.
+     */
+    public void initialize(ExploreSitesCategory category) {
+        super.initialize(TitleUtil.getTitleForDisplay(category.getTitle(), category.getUrl()),
+                SUPPORTED_OFFLINE, new BitmapDrawable(category.getIcon()), TITLE_LINES);
+        mCategory = category;
+    }
+
+    /** Retrieves url associated with this view. */
+    public String getUrl() {
+        return mCategory.getUrl();
+    }
+
+    /** Renders icon based on tile data.  */
+    public void renderIcon(ExploreSitesCategory category) {
+        mCategory = category;
+        setIconDrawable(new BitmapDrawable(getResources(), category.getIcon()));
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
new file mode 100644
index 0000000..2e1925e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java
@@ -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.
+
+package org.chromium.chrome.browser.explore_sites;
+
+import android.view.LayoutInflater;
+import android.view.View;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.suggestions.SuggestionsConfig.TileStyle;
+import org.chromium.chrome.browser.suggestions.TileGridLayout;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.ui.base.PageTransition;
+import org.chromium.ui.mojom.WindowOpenDisposition;
+
+import java.util.List;
+
+/**
+ * Describes a portion of UI responsible for rendering a group of categories.
+ * It abstracts general tasks related to initializing and fetching data for the UI.
+ */
+public class ExploreSitesSection {
+    private static final int MAX_TILES = 4;
+
+    @TileStyle
+    private int mStyle;
+    private Profile mProfile;
+    private NativePageNavigationDelegate mNavigationDelegate;
+    private TileGridLayout mExploreSection;
+
+    public ExploreSitesSection(View view, Profile profile,
+            NativePageNavigationDelegate navigationDelegate, @TileStyle int style) {
+        mProfile = profile;
+        mStyle = style;
+        mExploreSection = (TileGridLayout) view;
+        mExploreSection.setMaxRows(1);
+        mExploreSection.setMaxColumns(MAX_TILES);
+        mNavigationDelegate = navigationDelegate;
+        initialize();
+    }
+
+    private void initialize() {
+        ExploreSitesBridge.getEspCatalog(mProfile, this ::initializeCategoryTiles);
+    }
+
+    private void initializeCategoryTiles(List<ExploreSitesCategory> categoryList) {
+        if (categoryList == null) return;
+        if (categoryList.size() == 0) {
+            // TODO(dewittj): Remove this once the fetcher works.
+            categoryList.add(new ExploreSitesCategory(1, "this"));
+            categoryList.add(new ExploreSitesCategory(1, "this"));
+            categoryList.add(new ExploreSitesCategory(1, "this"));
+            categoryList.add(new ExploreSitesCategory(1, "More"));
+        }
+
+        int tileCount = 0;
+        for (final ExploreSitesCategory category : categoryList) {
+            tileCount++;
+            if (tileCount > MAX_TILES) break;
+            ExploreSitesCategoryTileView tileView;
+            if (mStyle == TileStyle.MODERN_CONDENSED) {
+                tileView = (ExploreSitesCategoryTileView) LayoutInflater
+                                   .from(mExploreSection.getContext())
+                                   .inflate(R.layout.explore_sites_category_tile_view_condensed,
+                                           mExploreSection, false);
+            } else {
+                tileView = (ExploreSitesCategoryTileView) LayoutInflater
+                                   .from(mExploreSection.getContext())
+                                   .inflate(R.layout.explore_sites_category_tile_view,
+                                           mExploreSection, false);
+            }
+
+            tileView.initialize(category);
+            mExploreSection.addView(tileView);
+            tileView.setOnClickListener((View v) -> onClicked(category, v));
+        }
+    }
+
+    private void onClicked(ExploreSitesCategory category, View v) {
+        mNavigationDelegate.openUrl(WindowOpenDisposition.CURRENT_TAB,
+                new LoadUrlParams(category.getUrl(), PageTransition.AUTO_BOOKMARK));
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java
index c1e8520..f277d6a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java
@@ -30,9 +30,8 @@
     }
 
     public void initialize(ExploreSitesSite site) {
-        super.initialize(site.getTitle(), site.getUrl(), /* showOfflineBadge = */ false,
-                getDrawableForBitmap(site.getIcon(), site.getTitle()), TITLE_LINES,
-                TileWithTextView.Style.MODERN);
+        super.initialize(site.getTitle(), /* showOfflineBadge = */ false,
+                getDrawableForBitmap(site.getIcon(), site.getTitle()), TITLE_LINES);
     }
 
     public void updateIcon(Bitmap iconImage, String text) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
index 2877e609..8a15338 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -29,6 +29,9 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider;
 import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection;
+import org.chromium.chrome.browser.explore_sites.ExploreSitesBridge;
+import org.chromium.chrome.browser.explore_sites.ExploreSitesSection;
+import org.chromium.chrome.browser.explore_sites.ExploreSitesVariation;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.native_page.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener;
@@ -86,7 +89,7 @@
     @Nullable
     private View mExploreSectionView; // View is null if explore flag is disabled.
     @Nullable
-    private ExperimentalExploreSitesSection mExploreSection; // Null when explore sites disabled.
+    private Object mExploreSection; // Null when explore sites disabled.
 
     private OnSearchBoxScrollListener mSearchBoxScrollListener;
 
@@ -185,8 +188,12 @@
         mSearchProviderLogoView = findViewById(R.id.search_provider_logo);
         mSearchBoxView = findViewById(R.id.search_box);
         insertSiteSectionView();
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.EXPLORE_SITES)) {
+
+        if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.ENABLED) {
+            mExploreSectionView = ((ViewStub) findViewById(R.id.explore_sites_stub)).inflate();
+        } else if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.EXPERIMENT) {
             ViewStub exploreStub = findViewById(R.id.explore_sites_stub);
+            exploreStub.setLayoutResource(R.layout.experimental_explore_sites_section);
             mExploreSectionView = exploreStub.inflate();
         }
 
@@ -233,7 +240,10 @@
         mSiteSectionViewHolder = SiteSection.createViewHolder(getSiteSectionView(), mUiConfig);
         mSiteSectionViewHolder.bindDataSource(mTileGroup, tileRenderer);
 
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.EXPLORE_SITES)) {
+        if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.ENABLED) {
+            mExploreSection = new ExploreSitesSection(mExploreSectionView, profile,
+                    mManager.getNavigationDelegate(), SuggestionsConfig.getTileStyle(mUiConfig));
+        } else if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.EXPERIMENT) {
             mExploreSection = new ExperimentalExploreSitesSection(
                     mExploreSectionView, profile, mManager.getNavigationDelegate());
         }
@@ -422,6 +432,12 @@
         mSiteSectionView = SiteSection.inflateSiteSection(this);
         ViewGroup.LayoutParams layoutParams = mSiteSectionView.getLayoutParams();
         layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
+        // If the explore sites section exists, then space it more closely.
+        if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.ENABLED) {
+            ((MarginLayoutParams) layoutParams).bottomMargin =
+                    getResources().getDimensionPixelOffset(
+                            R.dimen.tile_grid_layout_vertical_spacing);
+        }
         mSiteSectionView.setLayoutParams(layoutParams);
 
         int insertionPoint = indexOfChild(mMiddleSpacer) + 1;
@@ -878,6 +894,11 @@
             measureExactly(mSearchBoxView, width, mSearchBoxView.getMeasuredHeight());
             measureExactly(mSearchProviderLogoView,
                     width, mSearchProviderLogoView.getMeasuredHeight());
+
+            if (mExploreSectionView != null) {
+                measureExactly(mExploreSectionView, mSiteSectionView.getMeasuredWidth(),
+                        mExploreSectionView.getMeasuredHeight());
+            }
         } else if (mExploreSectionView != null) {
             final int exploreWidth = mExploreSectionView.getMeasuredWidth() - mTileGridLayoutBleed;
             measureExactly(mSearchBoxView, exploreWidth, mSearchBoxView.getMeasuredHeight());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
index 3628209..2f3e1401 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsConfig.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.suggestions;
 
 import android.content.res.Resources;
+import android.support.annotation.IntDef;
 import android.text.TextUtils;
 
 import org.chromium.base.ApiCompatibilityUtils;
@@ -12,12 +13,21 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
-import org.chromium.chrome.browser.widget.tile.TileWithTextView;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * Provides configuration details for suggestions.
  */
 public final class SuggestionsConfig {
+    @IntDef({TileStyle.MODERN, TileStyle.MODERN_CONDENSED})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TileStyle {
+        int MODERN = 1;
+        int MODERN_CONDENSED = 2;
+    }
+
     /**
      * Field trial parameter for referrer URL.
      * It must be kept in sync with //components/ntp_suggestions/features.cc
@@ -55,10 +65,10 @@
     /**
      * Returns the current tile style, that depends on the enabled features and the screen size.
      */
-    @TileWithTextView.Style
+    @TileStyle
     public static int getTileStyle(UiConfig uiConfig) {
-        return uiConfig.getCurrentDisplayStyle().isSmall() ? TileWithTextView.Style.MODERN_CONDENSED
-                                                           : TileWithTextView.Style.MODERN;
+        return uiConfig.getCurrentDisplayStyle().isSmall() ? TileStyle.MODERN_CONDENSED
+                                                           : TileStyle.MODERN;
     }
 
     private static boolean useCondensedTileLayout(boolean isScreenSmall) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsTileView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsTileView.java
index c007526d..ecefd83 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsTileView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsTileView.java
@@ -11,7 +11,6 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ntp.TitleUtil;
 import org.chromium.chrome.browser.widget.tile.TileWithTextView;
-import org.chromium.chrome.browser.widget.tile.TileWithTextView.Style;
 
 /**
  * The view for a site suggestion tile. Displays the title of the site beneath a large icon. If a
@@ -33,11 +32,10 @@
      * after inflation.
      * @param tile The tile that holds the data to populate this view.
      * @param titleLines The number of text lines to use for the tile title.
-     * @param tileStyle The visual style of the tile.
      */
-    public void initialize(Tile tile, int titleLines, @Style int tileStyle) {
+    public void initialize(Tile tile, int titleLines) {
         super.initialize(TitleUtil.getTitleForDisplay(tile.getTitle(), tile.getUrl()),
-                tile.getUrl(), tile.isOfflineAvailable(), tile.getIcon(), titleLines, tileStyle);
+                tile.isOfflineAvailable(), tile.getIcon(), titleLines);
         mData = tile.getData();
         setIconViewLayoutParams(tile);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java
index 3251907..b1c60e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileRenderer.java
@@ -24,9 +24,9 @@
 import org.chromium.chrome.browser.favicon.LargeIconBridge;
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.suggestions.SuggestionsConfig.TileStyle;
 import org.chromium.chrome.browser.util.ViewUtils;
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
-import org.chromium.chrome.browser.widget.tile.TileWithTextView;
 import org.chromium.components.feature_engagement.EventConstants;
 import org.chromium.components.feature_engagement.Tracker;
 
@@ -49,7 +49,7 @@
     private final ImageFetcher mImageFetcher;
     private final RoundedIconGenerator mIconGenerator;
 
-    @TileWithTextView.Style
+    @TileStyle
     private final int mStyle;
     private final int mTitleLinesCount;
     private final int mDesiredIconSize;
@@ -58,8 +58,8 @@
     @LayoutRes
     private final int mLayout;
 
-    public TileRenderer(Context context, @TileWithTextView.Style int style, int titleLines,
-            ImageFetcher imageFetcher) {
+    public TileRenderer(
+            Context context, @TileStyle int style, int titleLines, ImageFetcher imageFetcher) {
         mImageFetcher = imageFetcher;
         mStyle = style;
         mTitleLinesCount = titleLines;
@@ -133,7 +133,7 @@
         SuggestionsTileView tileView =
                 (SuggestionsTileView) LayoutInflater.from(parentView.getContext())
                         .inflate(mLayout, parentView, false);
-        tileView.initialize(tile, mTitleLinesCount, mStyle);
+        tileView.initialize(tile, mTitleLinesCount);
 
         // Note: It is important that the callbacks below don't keep a reference to the tile or
         // modify them as there is no guarantee that the same tile would be used to update the view.
@@ -206,9 +206,9 @@
     @LayoutRes
     private int getLayout() {
         switch (mStyle) {
-            case TileWithTextView.Style.MODERN:
+            case TileStyle.MODERN:
                 return R.layout.suggestions_tile_view;
-            case TileWithTextView.Style.MODERN_CONDENSED:
+            case TileStyle.MODERN_CONDENSED:
                 return R.layout.suggestions_tile_view_condensed;
         }
         assert false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index af08a45..0019d5b5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -148,6 +148,9 @@
     private static final ActionEvent ACCELERATOR_BUTTON_TAP_ACTION =
             new ActionEvent("MobileToolbarOmniboxAcceleratorTap");
 
+    /** The amount of time to show the Duet help bubble for. */
+    private static final int DUET_IPH_BUBBLE_SHOW_DURATION_MS = 6000;
+
     /**
      * The number of ms to wait before reporting to UMA omnibox interaction metrics.
      */
@@ -947,7 +950,7 @@
                         R.string.iph_duet_icons_moved, R.string.iph_duet_icons_moved, true,
                         new ViewRectProvider(mToolbar));
             }
-            bubble.setDismissOnTouchInteraction(true);
+            bubble.setAutoDismissTimeout(DUET_IPH_BUBBLE_SHOW_DURATION_MS);
             bubble.addOnDismissListener(
                     () -> tracker.dismissed(FeatureConstants.CHROME_DUET_FEATURE));
             bubble.show();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index 396dab2..dab6166 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -261,9 +261,6 @@
     /** Whether or not scroll events are currently being blocked for the 'velocity' swipe logic. */
     private boolean mVelocityLogicBlockSwipe;
 
-    /** Whether or not the slim peek UI should be used for the current sheet content. */
-    private boolean mUseSlimPeek;
-
     /**
      * An interface defining content that can be displayed inside of the bottom sheet for Chrome
      * Home.
@@ -312,11 +309,6 @@
         boolean isPeekStateEnabled();
 
         /**
-         * @return Whether a slimmer peek UI should be used for this content.
-         */
-        boolean useSlimPeek();
-
-        /**
          * @return The resource id of the content description for the bottom sheet. This is
          *         generally the name of the feature/content that is showing. 'Swipe down to close.'
          *         will be automatically appended after the content description.
@@ -802,9 +794,6 @@
         // If the desired content is already showing, do nothing.
         if (mSheetContent == content) return;
 
-        // TODO(twellington): Handle updates to the peek UI while the sheet is showing?
-        if (content != null && mUseSlimPeek != content.useSlimPeek()) updatePeekUI(content);
-
         List<Animator> animators = new ArrayList<>();
         mContentSwapAnimatorSet = new AnimatorSet();
         mContentSwapAnimatorSet.addListener(new AnimatorListenerAdapter() {
@@ -875,24 +864,6 @@
     }
 
     /**
-     * Updates the peek UI for the current BottomSheetcontent.
-     * @param content The current {@link BottomSheetContent}
-     */
-    private void updatePeekUI(BottomSheetContent content) {
-        mUseSlimPeek = content.useSlimPeek();
-
-        int peekHeightId = mUseSlimPeek ? R.dimen.bottom_control_container_slim_expanded_height
-                                        : R.dimen.bottom_control_container_peek_height;
-        mDefaultToolbarView.getLayoutParams().height =
-                getResources().getDimensionPixelSize(peekHeightId);
-
-        int toolbarHeightId = mUseSlimPeek ? R.dimen.bottom_control_container_slim_peek_height
-                                           : R.dimen.bottom_control_container_peek_height;
-        mToolbarHeight = getResources().getDimensionPixelSize(toolbarHeightId);
-        updateSheetStateRatios();
-    }
-
-    /**
      * Called when the animation to swap BottomSheetContent ends.
      * @param content The BottomSheetContent showing at the end of the animation.
      */
@@ -1022,8 +993,12 @@
                 mPersistentControlsToken);
 
         for (BottomSheetObserver o : mObservers) o.onSheetClosed(reason);
-        announceForAccessibility(getResources().getString(
-                getCurrentSheetContent().getSheetClosedAccessibilityStringId()));
+        // If the sheet contents are cleared out before #onSheetClosed is called, do not try to
+        // retrieve the accessibility string.
+        if (getCurrentSheetContent() != null) {
+            announceForAccessibility(getResources().getString(
+                    getCurrentSheetContent().getSheetClosedAccessibilityStringId()));
+        }
         clearFocus();
         mActivity.removeViewObscuringAllTabs(this);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java
index d6fea41..83d50f5c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/tile/TileWithTextView.java
@@ -6,7 +6,6 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
-import android.support.annotation.IntDef;
 import android.util.AttributeSet;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -14,22 +13,12 @@
 
 import org.chromium.chrome.R;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
 /**
  * The view for a tile with icon and text.
  *
  * Displays the title of the site beneath a large icon.
  */
 public class TileWithTextView extends FrameLayout {
-    @IntDef({Style.MODERN, Style.MODERN_CONDENSED})
-    @Retention(RetentionPolicy.SOURCE)
-    public @interface Style {
-        int MODERN = 1;
-        int MODERN_CONDENSED = 2;
-    }
-
     private TextView mTitleView;
     private ImageView mBadgeView;
     protected ImageView mIconView;
@@ -54,14 +43,11 @@
      * Initializes the view. This should be called immediately after inflation.
      *
      * @param title The title of the tile.
-     * @param url The url of the tile.
      * @param showOfflineBadge Whether to show the offline badge.
      * @param icon The icon to display on the tile.
      * @param titleLines The number of text lines to use for the tile title.
-     * @param tileStyle The visual style of the tile.
      */
-    public void initialize(String title, String url, boolean showOfflineBadge, Drawable icon,
-            int titleLines, @Style int tileStyle) {
+    public void initialize(String title, boolean showOfflineBadge, Drawable icon, int titleLines) {
         mTitleView.setLines(titleLines);
         mTitleView.setText(title);
         setOfflineBadgeVisibility(showOfflineBadge);
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 7197758..458f0a4 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -567,8 +567,10 @@
   "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardView.java",
   "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryCardViewHolderFactory.java",
   "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTile.java",
+  "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesCategoryTileView.java",
   "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPage.java",
   "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesPageLayout.java",
+  "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSection.java",
   "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesSite.java",
   "java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesTileView.java",
   "java/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtils.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java
index 42443ef3..3f3c8cb 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/TestBottomSheetContent.java
@@ -83,11 +83,6 @@
     }
 
     @Override
-    public boolean useSlimPeek() {
-        return false;
-    }
-
-    @Override
     public int getSheetContentDescriptionStringId() {
         return R.string.contextual_suggestions_button_description;
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java
index 9c6e4f4a..740e0fd 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupUnitTest.java
@@ -46,8 +46,8 @@
 import org.chromium.chrome.browser.native_page.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.cards.CardsVariationParameters;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
+import org.chromium.chrome.browser.suggestions.SuggestionsConfig.TileStyle;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
-import org.chromium.chrome.browser.widget.tile.TileWithTextView.Style;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.chrome.test.util.browser.suggestions.FakeMostVisitedSites;
 
@@ -84,7 +84,7 @@
 
         mImageFetcher = new FakeImageFetcher();
         mTileRenderer = new TileRenderer(
-                RuntimeEnvironment.application, Style.MODERN, TILE_TITLE_LINES, mImageFetcher);
+                RuntimeEnvironment.application, TileStyle.MODERN, TILE_TITLE_LINES, mImageFetcher);
         mMostVisitedSites = new FakeMostVisitedSites();
 
         doAnswer(invocation -> {
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index b4875eb..aee74e1 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4145,7 +4145,7 @@
     Place your finger
   </message>
   <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION" desc="The label that explains the location of the fingerprint sensor on the device.">
-    Touch the sensor with your index finger. It's on the top left of your Chromebook.
+    Touch the sensor with your finger. It's on the edge of your Chromebook.
   </message>
   <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_ENROLLMENT_PROGRESS_TITLE" desc="The title of the dialog that shows where the fingerprint sensor is.">
     Lift, then touch again
@@ -4184,7 +4184,7 @@
     Finger 3
   </message>
   <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER" desc="Text in the fingerprint setup screen telling users what to move finger to capture the different parts of fingerprint.">
-    Move your index finger slightly to add the different parts of your fingerprint.
+    Move your finger slightly to add the different parts of your fingerprint.
   </message>
   <message name="IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_TRY_AGAIN" desc="Text in the fingerprint setup screen telling users what to scan their finger again.">
     Try again.
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1
index 5830e6f7..4e1bc54 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_INSTRUCTION_MOVE_FINGER.png.sha1
@@ -1 +1 @@
-53b1e6993c638b4395accfbf4fb34a0d5cb943d2
\ No newline at end of file
+0aa420cbdd6f271aa13288688e3fe83347f649b2
\ No newline at end of file
diff --git a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1 b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1
index a6df5e7..4e1bc54 100644
--- a/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1
+++ b/chrome/app/chromeos_strings_grdp/IDS_OOBE_FINGERPINT_SETUP_SCREEN_SENSOR_DESCRIPTION.png.sha1
@@ -1 +1 @@
-9d151e643bd4a4a6c1ff3ef6fb84b0ad6da02fc8
\ No newline at end of file
+0aa420cbdd6f271aa13288688e3fe83347f649b2
\ No newline at end of file
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 59fe934..49e9cf3 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4793,7 +4793,7 @@
       <message name="IDS_NTP_CONFIRM_MSG_RESTORE_DEFAULTS" desc="The text label of the restore default shortcuts button when editing a custom link. (On the New Tab Page)">
         Restore default shortcuts
       </message>
-      <message name="IDS_NTP_CUSTOM_BG_CUSTOMIZE_BACKGROUND" desc="The title for the tooltip for background customization. (On the New Tab Page)">
+      <message name="IDS_NTP_CUSTOM_BG_CUSTOMIZE_BACKGROUND" desc="The title and aria-label for the tooltip for background customization. (On the New Tab Page)">
         Customize this page
       </message>
       <message name="IDS_NTP_CUSTOM_BG_GOOGLE_PHOTOS" desc="The text label of the Google Photos option for background customization. (On the New Tab Page)">
diff --git a/chrome/app/nibs/Toolbar.xib b/chrome/app/nibs/Toolbar.xib
index 5e2eb5d..bc6c940 100644
--- a/chrome/app/nibs/Toolbar.xib
+++ b/chrome/app/nibs/Toolbar.xib
@@ -76,10 +76,10 @@
                         <action selector="commandDispatchUsingKeyModifiers:" target="-1" id="155"/>
                     </connections>
                 </button>
-                <textField focusRingType="exterior" verticalHuggingPriority="750" tag="33004" id="4" customClass="AutocompleteTextField">
+                <textField focusRingType="exterior" verticalHuggingPriority="750" tag="33004" id="4">
                     <rect key="frame" x="119" y="4" width="454" height="29"/>
                     <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
-                    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="exterior" alignment="left" drawsBackground="YES" id="13" customClass="AutocompleteTextFieldCell">
+                    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" focusRingType="exterior" alignment="left" drawsBackground="YES" id="13">
                         <font key="font" metaFont="system"/>
                         <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
                         <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
diff --git a/chrome/app/theme/default_100_percent/legacy/download_animation_begin.png b/chrome/app/theme/default_100_percent/legacy/download_animation_begin.png
deleted file mode 100644
index 0343b14..0000000
--- a/chrome/app/theme/default_100_percent/legacy/download_animation_begin.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/legacy/download_animation_begin.png b/chrome/app/theme/default_200_percent/legacy/download_animation_begin.png
deleted file mode 100644
index 91ea7595..0000000
--- a/chrome/app/theme/default_200_percent/legacy/download_animation_begin.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 048ce1c..d01bf93 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -96,9 +96,6 @@
         <structure type="chrome_scaled_image" name="IDR_DEVICE_DISABLED" file="cros/device_disabled.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_DOWNLOADS_FAVICON" file="common/favicon_downloads.png" />
-      <if expr="is_macosx">
-        <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_ANIMATION_BEGIN" file="legacy/download_animation_begin.png" />
-      </if>
       <if expr="chromeos">
         <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_ANNOTATE" file="cros/downloads/annotate.png" />
         <structure type="chrome_scaled_image" name="IDR_DOWNLOAD_NOTIFICATION_MENU_CANCEL" file="cros/downloads/cancel.png" />
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 854dc50..baf8b49 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1319,6 +1319,8 @@
     "resource_coordinator/browser_child_process_watcher.h",
     "resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc",
     "resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h",
+    "resource_coordinator/discard_before_unload_helper.cc",
+    "resource_coordinator/discard_before_unload_helper.h",
     "resource_coordinator/exponential_moving_average.cc",
     "resource_coordinator/exponential_moving_average.h",
     "resource_coordinator/page_signal_receiver.cc",
@@ -1538,6 +1540,8 @@
     "sync/model_type_store_service_factory.h",
     "sync/profile_sync_service_factory.cc",
     "sync/profile_sync_service_factory.h",
+    "sync/session_sync_service_factory.cc",
+    "sync/session_sync_service_factory.h",
     "sync/sessions/sync_sessions_router_tab_helper.cc",
     "sync/sessions/sync_sessions_router_tab_helper.h",
     "sync/sessions/sync_sessions_web_contents_router.cc",
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
index cf8af34..a305a01 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -21,6 +21,7 @@
 #include "ui/android/resources/resource_manager_impl.h"
 #include "ui/android/view_android.h"
 #include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/geometry/size_conversions.h"
 
 using base::android::JavaParamRef;
 using base::android::JavaRef;
@@ -33,12 +34,18 @@
     : SceneLayer(env, jobj),
       env_(env),
       object_(jobj),
-      base_page_brightness_(1.0f),
+      color_overlay_(cc::SolidColorLayer::Create()),
       content_container_(cc::Layer::Create()) {
   // Responsible for moving the base page without modifying the layer itself.
   content_container_->SetIsDrawable(true);
   content_container_->SetPosition(gfx::PointF(0.0f, 0.0f));
   layer()->AddChild(content_container_);
+
+  color_overlay_->SetIsDrawable(true);
+  color_overlay_->SetOpacity(0.0f);
+  color_overlay_->SetBackgroundColor(SK_ColorBLACK);
+  color_overlay_->SetPosition(gfx::PointF(0.f, 0.f));
+  layer()->AddChild(color_overlay_);
 }
 
 void ContextualSearchSceneLayer::CreateContextualSearchLayer(
@@ -76,6 +83,8 @@
     jint bar_banner_ripple_resource_id,
     jint bar_banner_text_resource_id,
     jfloat dp_to_px,
+    jfloat layout_width,
+    jfloat layout_height,
     jfloat base_page_brightness,
     jfloat base_page_offset,
     const JavaParamRef<jobject>& jweb_contents,
@@ -143,15 +152,9 @@
       web_contents ? web_contents->GetNativeView()->GetLayer() : nullptr;
 
   // Fade the base page out.
-  if (base_page_brightness_ != base_page_brightness) {
-    base_page_brightness_ = base_page_brightness;
-    cc::FilterOperations filters;
-    if (base_page_brightness < 1.f) {
-      filters.Append(
-          cc::FilterOperation::CreateBrightnessFilter(base_page_brightness));
-    }
-    content_container_->SetFilters(filters);
-  }
+  color_overlay_->SetOpacity(1.f - base_page_brightness);
+  color_overlay_->SetBounds(
+      gfx::ToCeiledSize(gfx::SizeF(layout_width, layout_height)));
 
   // Move the base page contents up.
   content_container_->SetPosition(gfx::PointF(0.0f, base_page_offset));
@@ -236,9 +239,7 @@
     contextual_search_layer_->layer()->SetHideLayerAndSubtree(true);
   }
   // Reset base page brightness.
-  cc::FilterOperations filters;
-  filters.Append(cc::FilterOperation::CreateBrightnessFilter(1.0f));
-  content_container_->SetFilters(filters);
+  color_overlay_->SetOpacity(0.f);
   // Reset base page offset.
   content_container_->SetPosition(gfx::PointF(0.0f, 0.0f));
 }
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
index b1ead56b..0d0ec1b1 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h
@@ -17,6 +17,7 @@
 
 namespace cc {
 class Layer;
+class SolidColorLayer;
 }
 
 namespace android {
@@ -53,6 +54,8 @@
       jint bar_banner_ripple_resource_id,
       jint bar_banner_text_resource_id,
       jfloat dp_to_px,
+      jfloat layout_width,
+      jfloat layout_height,
       jfloat base_page_brightness,
       jfloat base_page_offset,
       const base::android::JavaParamRef<jobject>& jweb_contents,
@@ -122,11 +125,12 @@
 
   JNIEnv* env_;
   base::android::ScopedJavaGlobalRef<jobject> object_;
-  float base_page_brightness_;
   std::string thumbnail_url_;
   std::unique_ptr<BitmapFetcher> fetcher_;
 
   scoped_refptr<ContextualSearchLayer> contextual_search_layer_;
+  // Responsible for fading the base page content.
+  scoped_refptr<cc::SolidColorLayer> color_overlay_;
   scoped_refptr<cc::Layer> content_container_;
 
   DISALLOW_COPY_AND_ASSIGN(ContextualSearchSceneLayer);
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
index 89c947e1..ec5af60 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.cc
@@ -36,7 +36,8 @@
 #include "content/public/browser/web_contents.h"
 #include "net/base/escape.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_fetcher.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 #include "url/gurl.h"
 
 using content::RenderFrameHost;
@@ -73,20 +74,19 @@
 // The version of the Contextual Cards API that we want to invoke.
 const int kContextualCardsUrlActions = 3;
 
-}  // namespace
+const int kResponseCodeUninitialized = -1;
 
-// URLFetcher ID, only used for tests: we only have one kind of fetcher.
-const int ContextualSearchDelegate::kContextualSearchURLFetcherID = 1;
+}  // namespace
 
 // Handles tasks for the ContextualSearchManager in a separable, testable way.
 ContextualSearchDelegate::ContextualSearchDelegate(
-    net::URLRequestContextGetter* url_request_context,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     TemplateURLService* template_url_service,
     const ContextualSearchDelegate::SearchTermResolutionCallback&
         search_term_callback,
     const ContextualSearchDelegate::SurroundingTextCallback&
         surrounding_text_callback)
-    : url_request_context_(url_request_context),
+    : url_loader_factory_(std::move(url_loader_factory)),
       template_url_service_(template_url_service),
       search_term_callback_(search_term_callback),
       surrounding_text_callback_(surrounding_text_callback) {
@@ -132,7 +132,7 @@
 
   // Immediately cancel any request that's in flight, since we're building a new
   // context (and the response disposes of any existing context).
-  search_term_fetcher_.reset();
+  url_loader_.reset();
 
   // Decide if the URL should be sent with the context.
   GURL page_url(web_contents->GetURL());
@@ -149,47 +149,47 @@
   GURL request_url(BuildRequestUrl(context_->GetHomeCountry()));
   DCHECK(request_url.is_valid());
 
-  // Reset will delete any previous fetcher, and we won't get any callback.
-  search_term_fetcher_.reset(
-      net::URLFetcher::Create(kContextualSearchURLFetcherID, request_url,
-                              net::URLFetcher::GET, this).release());
-  search_term_fetcher_->SetRequestContext(url_request_context_);
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = request_url;
 
-  // Add Chrome experiment state to the request headers.
-  net::HttpRequestHeaders headers;
-  variations::AppendVariationHeadersUnknownSignedIn(
-      search_term_fetcher_->GetOriginalURL(),
-      variations::InIncognito::kNo,  // Impossible to be incognito at this
-                                     // point.
-      &headers);
-  search_term_fetcher_->SetExtraRequestHeaders(headers.ToString());
-
-  SetDiscourseContextAndAddToHeader(*context_);
+  // Populates the discourse context and adds it to the HTTP header of the
+  // search term resolution request.
+  resource_request->headers.AddHeadersFromString(
+      GetDiscourseContext(*context_));
 
   // Disable cookies for this request.
-  search_term_fetcher_->SetAllowCredentials(false);
+  resource_request->allow_credentials = false;
 
-  search_term_fetcher_->Start();
+  // Add Chrome experiment state to the request headers.
+  // Reset will delete any previous loader, and we won't get any callback.
+  url_loader_ =
+      variations::CreateSimpleURLLoaderWithVariationsHeadersUnknownSignedIn(
+          std::move(resource_request),
+          variations::InIncognito::kNo,  // Impossible to be incognito at this
+                                         // point.
+          NO_TRAFFIC_ANNOTATION_YET);
+
+  url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      url_loader_factory_.get(),
+      base::BindOnce(&ContextualSearchDelegate::OnUrlLoadComplete,
+                     base::Unretained(this)));
 }
 
-void ContextualSearchDelegate::OnURLFetchComplete(
-    const net::URLFetcher* source) {
-  if (context_ == nullptr)
+void ContextualSearchDelegate::OnUrlLoadComplete(
+    std::unique_ptr<std::string> response_body) {
+  if (!context_)
     return;
 
-  DCHECK(source == search_term_fetcher_.get());
-  int response_code = source->GetResponseCode();
+  int response_code = kResponseCodeUninitialized;
+  if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) {
+    response_code = url_loader_->ResponseInfo()->headers->response_code();
+  }
 
   std::unique_ptr<ResolvedSearchTerm> resolved_search_term(
       new ResolvedSearchTerm(response_code));
-  if (source->GetStatus().is_success() && response_code == net::HTTP_OK) {
-    std::string response;
-    bool has_string_response = source->GetResponseAsString(&response);
-    DCHECK(has_string_response);
-    if (has_string_response && context_ != nullptr) {
-      resolved_search_term =
-          GetResolvedSearchTermFromJson(response_code, response);
-    }
+  if (response_body && response_code == net::HTTP_OK) {
+    resolved_search_term =
+        GetResolvedSearchTermFromJson(response_code, *response_body);
   }
   search_term_callback_.Run(*resolved_search_term);
 }
@@ -234,7 +234,7 @@
       end_adjust = mention_end - context_->GetEndOffset();
     }
   }
-  bool is_invalid = response_code == net::URLFetcher::RESPONSE_CODE_INVALID;
+  bool is_invalid = response_code == kResponseCodeUninitialized;
   return std::unique_ptr<ResolvedSearchTerm>(new ResolvedSearchTerm(
       is_invalid, response_code, search_term, display_text, alternate_term, mid,
       prevent_preload == kDoPreventPreloadValue, start_adjust, end_adjust,
@@ -325,11 +325,6 @@
                                  selection_end);
 }
 
-void ContextualSearchDelegate::SetDiscourseContextAndAddToHeader(
-    const ContextualSearchContext& context) {
-  search_term_fetcher_->AddExtraRequestHeader(GetDiscourseContext(context));
-}
-
 std::string ContextualSearchDelegate::GetDiscourseContext(
     const ContextualSearchContext& context) {
   discourse_context::ClientDiscourseContext proto;
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate.h b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
index f18bc89..55c2050 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate.h
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate.h
@@ -17,15 +17,15 @@
 #include "base/values.h"
 #include "chrome/browser/android/contextualsearch/contextual_search_context.h"
 #include "chrome/browser/android/contextualsearch/resolved_search_term.h"
-#include "net/url_request/url_fetcher_delegate.h"
 
 namespace content {
 class WebContents;
 }
 
-namespace net {
-class URLRequestContextGetter;
-}  // namespace net
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
+}  // namespace network
 
 class Profile;
 class TemplateURLService;
@@ -34,8 +34,7 @@
 // Handles tasks for the ContextualSearchManager in a separable and testable
 // way, without the complication of being connected to a Java object.
 class ContextualSearchDelegate
-    : public net::URLFetcherDelegate,
-      public base::SupportsWeakPtr<ContextualSearchDelegate> {
+    : public base::SupportsWeakPtr<ContextualSearchDelegate> {
  public:
   // Provides the Resolved Search Term, called when the Resolve Request returns.
   typedef base::Callback<void(const ResolvedSearchTerm&)>
@@ -45,17 +44,14 @@
       void(const std::string&, const base::string16&, size_t, size_t)>
       SurroundingTextCallback;
 
-  // ID used in creating URLFetcher for Contextual Search results.
-  static const int kContextualSearchURLFetcherID;
-
   // Constructs a delegate that will always call back to the given callbacks
   // when search term resolution or surrounding text responses are available.
   ContextualSearchDelegate(
-      net::URLRequestContextGetter* url_request_context,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       TemplateURLService* template_url_service,
       const SearchTermResolutionCallback& search_term_callback,
       const SurroundingTextCallback& surrounding_callback);
-  ~ContextualSearchDelegate() override;
+  virtual ~ContextualSearchDelegate();
 
   // Gathers surrounding text and saves it locally in the given context.
   void GatherAndSaveSurroundingText(
@@ -101,8 +97,7 @@
   FRIEND_TEST_ALL_PREFIXES(ContextualSearchDelegateTest,
                            DecodeSearchTermFromJsonResponse);
 
-  // net::URLFetcherDelegate:
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
+  void OnUrlLoadComplete(std::unique_ptr<std::string> response_body);
 
   // Resolves the search term specified by the current context.
   // Only needed for tests.  TODO(donnd): make private and friend?
@@ -124,11 +119,6 @@
     int start_offset,
     int end_offset);
 
-  // Populates the discourse context and adds it to the HTTP header of the
-  // search term resolution request.
-  void SetDiscourseContextAndAddToHeader(
-      const ContextualSearchContext& context);
-
   // Populates and returns the discourse context.
   std::string GetDiscourseContext(const ContextualSearchContext& context);
 
@@ -191,10 +181,10 @@
   }
 
   // The current request in progress, or NULL.
-  std::unique_ptr<net::URLFetcher> search_term_fetcher_;
+  std::unique_ptr<network::SimpleURLLoader> url_loader_;
 
-  // Holds the URL request context. Not owned.
-  net::URLRequestContextGetter* url_request_context_;
+  // Holds the URL loader factory.
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
   // Holds the TemplateURLService. Not owned.
   TemplateURLService* template_url_service_;
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
index 283c9d7..b405d9860 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
@@ -22,8 +22,8 @@
 #include "chrome/common/chrome_switches.h"
 #include "components/search_engines/template_url_service.h"
 #include "net/base/escape.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::ListValue;
@@ -42,11 +42,12 @@
 
  protected:
   void SetUp() override {
-    request_context_ =
-        new net::TestURLRequestContextGetter(io_message_loop_.task_runner());
+    test_shared_url_loader_factory_ =
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            &test_url_loader_factory_);
     template_url_service_.reset(CreateTemplateURLService());
     delegate_.reset(new ContextualSearchDelegate(
-        request_context_.get(), template_url_service_.get(),
+        test_shared_url_loader_factory_, template_url_service_.get(),
         base::Bind(
             &ContextualSearchDelegateTest::recordSearchTermResolutionResponse,
             base::Unretained(this)),
@@ -56,7 +57,6 @@
   }
 
   void TearDown() override {
-    fetcher_ = NULL;
     is_invalid_ = true;
     response_code_ = -1;
     search_term_ = "invalid";
@@ -96,10 +96,7 @@
     test_context_->SetSelectionSurroundings(start_offset, end_offset,
                                             surrounding_text);
     delegate_->ResolveSearchTermFromContext();
-    fetcher_ = test_factory_.GetFetcherByID(
-        ContextualSearchDelegate::kContextualSearchURLFetcherID);
-    ASSERT_TRUE(fetcher_);
-    ASSERT_TRUE(fetcher());
+    ASSERT_TRUE(test_url_loader_factory_.GetPendingRequest(0));
   }
 
   // Allows using the vertical bar "|" as a quote character, which makes
@@ -113,11 +110,9 @@
   void CreateDefaultSearchWithAdditionalJsonData(
       const std::string additional_json_data) {
     CreateDefaultSearchContextAndRequestSearchTerm();
-    fetcher()->set_response_code(200);
     std::string response =
         escapeBarQuoted("{|search_term|:|obama|" + additional_json_data + "}");
-    fetcher()->SetResponseString(response);
-    fetcher()->delegate()->OnURLFetchComplete(fetcher());
+    SimulateResponseReturned(response);
 
     EXPECT_FALSE(is_invalid());
     EXPECT_EQ(200, response_code());
@@ -144,30 +139,29 @@
     delegate_->OnTextSurroundingSelectionAvailable(base::string16(), 1, 2);
   }
 
-  // Call the OnURLFetchComplete to simulate the end of a Resolve request.
-  // Cannot be in an actual test because OnTextSurroundingSelectionAvailable
-  // is private.
-  void CallOnURLFetchComplete() {
-    delegate_->OnURLFetchComplete(delegate_->search_term_fetcher_.get());
-  }
-
   void CallResolveSearchTermFromContext() {
     delegate_->ResolveSearchTermFromContext();
   }
 
-  void SetResponseStringAndFetch(const std::string& selected_text,
-                                 const std::string& mentions_start,
-                                 const std::string& mentions_end) {
-    fetcher()->set_response_code(200);
-      fetcher()->SetResponseString(
-          ")]}'\n"
-          "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\","
-          "\"info_text\":\"44th U.S. President\","
-          "\"display_text\":\"Barack Obama\","
-          "\"mentions\":[" + mentions_start + ","+ mentions_end + "],"
-          "\"selected_text\":\"" + selected_text + "\","
-          "\"resolved_term\":\"barack obama\"}");
-      fetcher()->delegate()->OnURLFetchComplete(fetcher());
+  void SetResponseStringAndSimulateResponse(const std::string& selected_text,
+                                            const std::string& mentions_start,
+                                            const std::string& mentions_end) {
+    std::string response = std::string(
+        ")]}'\n"
+        "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\","
+        "\"info_text\":\"44th U.S. President\","
+        "\"display_text\":\"Barack Obama\","
+        "\"mentions\":[" + mentions_start + "," + mentions_end + "],"
+        "\"selected_text\":\"" + selected_text + "\","
+        "\"resolved_term\":\"barack obama\"}");
+    SimulateResponseReturned(response);
+  }
+
+  void SimulateResponseReturned(const std::string& response) {
+    auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
+    test_url_loader_factory_.SimulateResponseForPendingRequest(
+        pending_request->request.url.spec(), response);
+    base::RunLoop().RunUntilIdle();
   }
 
   void SetSurroundingContext(const base::string16& surrounding_text,
@@ -184,13 +178,13 @@
   // Gets the Client Discourse Context proto from the request header.
   discourse_context::ClientDiscourseContext GetDiscourseContextFromRequest() {
     discourse_context::ClientDiscourseContext cdc;
-    // Make sure we can get the actual raw headers from the fake fetcher.
-    net::HttpRequestHeaders fetch_headers;
-    fetcher()->GetExtraRequestHeaders(&fetch_headers);
-    if (fetch_headers.HasHeader(kDiscourseContextHeaderName)) {
+    // Make sure we can get the actual raw headers from the url loader.
+    auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
+    net::HttpRequestHeaders request_headers = pending_request->request.headers;
+    if (request_headers.HasHeader(kDiscourseContextHeaderName)) {
       std::string actual_header_value;
-      fetch_headers.GetHeader(kDiscourseContextHeaderName,
-                              &actual_header_value);
+      request_headers.GetHeader(kDiscourseContextHeaderName,
+                                &actual_header_value);
 
       // Unescape, since the server memoizer expects a web-safe encoding.
       std::string unescaped_header = actual_header_value;
@@ -218,7 +212,6 @@
     return result;
   }
 
-  net::TestURLFetcher* fetcher() { return fetcher_; }
   bool is_invalid() { return is_invalid_; }
   int response_code() { return response_code_; }
   std::string search_term() { return search_term_; }
@@ -235,6 +228,8 @@
   // The delegate under test.
   std::unique_ptr<ContextualSearchDelegate> delegate_;
 
+  network::TestURLLoaderFactory test_url_loader_factory_;
+
  private:
   void recordSearchTermResolutionResponse(
       const ResolvedSearchTerm& resolved_search_term) {
@@ -273,10 +268,9 @@
   std::string context_language_;
 
   base::MessageLoopForIO io_message_loop_;
-  net::TestURLFetcherFactory test_factory_;
-  net::TestURLFetcher* fetcher_;
   std::unique_ptr<TemplateURLService> template_url_service_;
-  scoped_refptr<net::TestURLRequestContextGetter> request_context_;
+  scoped_refptr<network::SharedURLLoaderFactory>
+      test_shared_url_loader_factory_;
 
   // Will be owned by the delegate.
   ContextualSearchContext* test_context_;
@@ -286,14 +280,13 @@
 
 TEST_F(ContextualSearchDelegateTest, NormalFetchWithXssiEscape) {
   CreateDefaultSearchContextAndRequestSearchTerm();
-  fetcher()->set_response_code(200);
-  fetcher()->SetResponseString(
+  std::string response(
       ")]}'\n"
       "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\","
       "\"info_text\":\"44th U.S. President\","
       "\"display_text\":\"Barack Obama\", \"mentions\":[0,15],"
       "\"selected_text\":\"obama\", \"resolved_term\":\"barack obama\"}");
-  fetcher()->delegate()->OnURLFetchComplete(fetcher());
+  SimulateResponseReturned(response);
 
   EXPECT_FALSE(is_invalid());
   EXPECT_EQ(200, response_code());
@@ -305,13 +298,12 @@
 
 TEST_F(ContextualSearchDelegateTest, NormalFetchWithoutXssiEscape) {
   CreateDefaultSearchContextAndRequestSearchTerm();
-  fetcher()->set_response_code(200);
-  fetcher()->SetResponseString(
+  std::string response(
       "{\"mid\":\"/m/02mjmr\", \"search_term\":\"obama\","
       "\"info_text\":\"44th U.S. President\","
       "\"display_text\":\"Barack Obama\", \"mentions\":[0,15],"
       "\"selected_text\":\"obama\", \"resolved_term\":\"barack obama\"}");
-  fetcher()->delegate()->OnURLFetchComplete(fetcher());
+  SimulateResponseReturned(response);
 
   EXPECT_FALSE(is_invalid());
   EXPECT_EQ(200, response_code());
@@ -323,11 +315,10 @@
 
 TEST_F(ContextualSearchDelegateTest, ResponseWithNoDisplayText) {
   CreateDefaultSearchContextAndRequestSearchTerm();
-  fetcher()->set_response_code(200);
-  fetcher()->SetResponseString(
+  std::string response(
       "{\"mid\":\"/m/02mjmr\",\"search_term\":\"obama\","
       "\"mentions\":[0,15]}");
-  fetcher()->delegate()->OnURLFetchComplete(fetcher());
+  SimulateResponseReturned(response);
 
   EXPECT_FALSE(is_invalid());
   EXPECT_EQ(200, response_code());
@@ -339,11 +330,10 @@
 
 TEST_F(ContextualSearchDelegateTest, ResponseWithPreventPreload) {
   CreateDefaultSearchContextAndRequestSearchTerm();
-  fetcher()->set_response_code(200);
-  fetcher()->SetResponseString(
+  std::string response(
       "{\"mid\":\"/m/02mjmr\",\"search_term\":\"obama\","
       "\"mentions\":[0,15],\"prevent_preload\":\"1\"}");
-  fetcher()->delegate()->OnURLFetchComplete(fetcher());
+  SimulateResponseReturned(response);
 
   EXPECT_FALSE(is_invalid());
   EXPECT_EQ(200, response_code());
@@ -355,9 +345,8 @@
 
 TEST_F(ContextualSearchDelegateTest, NonJsonResponse) {
   CreateDefaultSearchContextAndRequestSearchTerm();
-  fetcher()->set_response_code(200);
-  fetcher()->SetResponseString("Non-JSON Response");
-  fetcher()->delegate()->OnURLFetchComplete(fetcher());
+  std::string response("Non-JSON Response");
+  SimulateResponseReturned(response);
 
   EXPECT_FALSE(is_invalid());
   EXPECT_EQ(200, response_code());
@@ -369,8 +358,11 @@
 
 TEST_F(ContextualSearchDelegateTest, InvalidResponse) {
   CreateDefaultSearchContextAndRequestSearchTerm();
-  fetcher()->set_response_code(net::URLFetcher::RESPONSE_CODE_INVALID);
-  fetcher()->delegate()->OnURLFetchComplete(fetcher());
+  auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
+  test_url_loader_factory_.SimulateResponseForPendingRequest(
+      pending_request->request.url, network::URLLoaderCompletionStatus(net::OK),
+      network::ResourceResponseHead(), std::string());
+  base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(do_prevent_preload());
   EXPECT_TRUE(is_invalid());
@@ -380,7 +372,7 @@
   base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
   std::string selected_text = "Barack";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 6);
-  SetResponseStringAndFetch(selected_text, "0", "12");
+  SetResponseStringAndSimulateResponse(selected_text, "0", "12");
 
   EXPECT_EQ(0, start_adjust());
   EXPECT_EQ(6, end_adjust());
@@ -390,7 +382,7 @@
   base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
   std::string selected_text = "Obama";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 7, 12);
-  SetResponseStringAndFetch(selected_text, "0", "12");
+  SetResponseStringAndSimulateResponse(selected_text, "0", "12");
 
   EXPECT_EQ(-7, start_adjust());
   EXPECT_EQ(0, end_adjust());
@@ -400,7 +392,7 @@
   base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
   std::string selected_text = "Ob";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 7, 9);
-  SetResponseStringAndFetch(selected_text, "0", "12");
+  SetResponseStringAndSimulateResponse(selected_text, "0", "12");
 
   EXPECT_EQ(-7, start_adjust());
   EXPECT_EQ(3, end_adjust());
@@ -410,7 +402,7 @@
   base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
   std::string selected_text = "Ob";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 7, 9);
-  SetResponseStringAndFetch(selected_text, "0", "200");
+  SetResponseStringAndSimulateResponse(selected_text, "0", "200");
 
   EXPECT_EQ(0, start_adjust());
   EXPECT_EQ(0, end_adjust());
@@ -421,7 +413,7 @@
   std::string selected_text = "Ob";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding,
                                           0xffffffff, 0xffffffff - 2);
-  SetResponseStringAndFetch(selected_text, "0", "12");
+  SetResponseStringAndSimulateResponse(selected_text, "0", "12");
 
   EXPECT_EQ(0, start_adjust());
   EXPECT_EQ(0, end_adjust());
@@ -431,7 +423,7 @@
   base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
   std::string selected_text = "Ob";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 12);
-  SetResponseStringAndFetch(selected_text, "12", "14");
+  SetResponseStringAndSimulateResponse(selected_text, "12", "14");
 
   EXPECT_EQ(0, start_adjust());
   EXPECT_EQ(0, end_adjust());
@@ -442,7 +434,7 @@
   std::string selected_text = "Ob";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding,
                                           0xffffffff, 0xffffffff - 2);
-  SetResponseStringAndFetch(selected_text, "0", "268435455");
+  SetResponseStringAndSimulateResponse(selected_text, "0", "268435455");
 
   EXPECT_EQ(0, start_adjust());
   EXPECT_EQ(0, end_adjust());
@@ -453,7 +445,7 @@
   std::string selected_text = "Ob";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding,
                                           268435450, 268435455);
-  SetResponseStringAndFetch(selected_text, "268435440", "268435455");
+  SetResponseStringAndSimulateResponse(selected_text, "268435440", "268435455");
 
   EXPECT_EQ(-10, start_adjust());
   EXPECT_EQ(0, end_adjust());
@@ -463,7 +455,7 @@
   base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
   std::string selected_text = "Barack Obama just";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 17);
-  SetResponseStringAndFetch(selected_text, "0", "12");
+  SetResponseStringAndSimulateResponse(selected_text, "0", "12");
 
   EXPECT_EQ(0, start_adjust());
   EXPECT_EQ(-5, end_adjust());
@@ -473,7 +465,7 @@
   base::string16 surrounding = base::UTF8ToUTF16("Barack Obama just spoke.");
   std::string selected_text = "Barack Obama just";
   CreateSearchContextAndRequestSearchTerm(selected_text, surrounding, 0, 17);
-  SetResponseStringAndFetch(selected_text, "5", "5");
+  SetResponseStringAndSimulateResponse(selected_text, "5", "5");
 
   EXPECT_EQ(0, start_adjust());
   EXPECT_EQ(0, end_adjust());
@@ -568,12 +560,11 @@
 
 TEST_F(ContextualSearchDelegateTest, ResponseWithLanguage) {
   CreateDefaultSearchContextAndRequestSearchTerm();
-  fetcher()->set_response_code(200);
-  fetcher()->SetResponseString(
+  std::string response(
       "{\"mid\":\"/m/02mjmr\",\"search_term\":\"obama\","
       "\"mentions\":[0,15],\"prevent_preload\":\"1\", "
       "\"lang\":\"de\"}");
-  fetcher()->delegate()->OnURLFetchComplete(fetcher());
+  SimulateResponseReturned(response);
 
   EXPECT_FALSE(is_invalid());
   EXPECT_EQ(200, response_code());
@@ -616,7 +607,11 @@
   CreateTestContext();
   CallResolveSearchTermFromContext();
   DestroyTestContext();
-  CallOnURLFetchComplete();
+
+  std::string response("Any response as it does not matter here.");
+  SimulateResponseReturned(response);
+
+  EXPECT_TRUE(is_invalid());
 }
 
 // Test that we can destroy the context while gathering surrounding text.
diff --git a/chrome/browser/android/contextualsearch/contextual_search_manager.cc b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
index da9dd3d..1bc3e648 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_manager.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_manager.cc
@@ -25,6 +25,7 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "jni/ContextualSearchManager_jni.h"
 #include "net/url_request/url_fetcher_impl.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/service_manager/public/cpp/binder_registry.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 
@@ -84,7 +85,7 @@
       env, obj, reinterpret_cast<intptr_t>(this));
   Profile* profile = ProfileManager::GetActiveUserProfile();
   delegate_.reset(new ContextualSearchDelegate(
-      profile->GetRequestContext(),
+      profile->GetURLLoaderFactory(),
       TemplateURLServiceFactory::GetForProfile(profile),
       base::Bind(&ContextualSearchManager::OnSearchTermResolutionResponse,
                  base::Unretained(this)),
diff --git a/chrome/browser/android/explore_sites/explore_sites_bridge.cc b/chrome/browser/android/explore_sites/explore_sites_bridge.cc
index b259691..7da43f5 100644
--- a/chrome/browser/android/explore_sites/explore_sites_bridge.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_bridge.cc
@@ -9,6 +9,7 @@
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
 #include "base/android/scoped_java_ref.h"
+#include "chrome/browser/android/explore_sites/explore_sites_feature.h"
 #include "chrome/browser/android/explore_sites/explore_sites_service.h"
 #include "chrome/browser/android/explore_sites/explore_sites_service_factory.h"
 #include "chrome/browser/android/explore_sites/explore_sites_types.h"
@@ -75,4 +76,11 @@
                      ScopedJavaGlobalRef<jobject>(j_callback_obj)));
 }
 
+// static
+jint JNI_ExploreSitesBridge_GetVariation(JNIEnv* env,
+                                         const JavaParamRef<jclass>& j_caller) {
+  return static_cast<jint>(
+      chrome::android::explore_sites::GetExploreSitesVariation());
+}
+
 }  // namespace explore_sites
diff --git a/chrome/browser/android/explore_sites/explore_sites_feature.h b/chrome/browser/android/explore_sites/explore_sites_feature.h
index 121815a4f..676f32c5 100644
--- a/chrome/browser/android/explore_sites/explore_sites_feature.h
+++ b/chrome/browser/android/explore_sites/explore_sites_feature.h
@@ -13,6 +13,8 @@
 
 extern const char kExploreSitesVariationExperimental[];
 
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.explore_sites
 enum class ExploreSitesVariation { ENABLED, EXPERIMENT, DISABLED };
 
 ExploreSitesVariation GetExploreSitesVariation();
diff --git a/chrome/browser/chromeos/arc/arc_util.cc b/chrome/browser/chromeos/arc/arc_util.cc
index 5a75249a..f1b3952e 100644
--- a/chrome/browser/chromeos/arc/arc_util.cc
+++ b/chrome/browser/chromeos/arc/arc_util.cc
@@ -20,7 +20,7 @@
 #include "base/strings/string_util.h"
 #include "base/sys_info.h"
 #include "base/task/post_task.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
 #include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
@@ -86,7 +86,7 @@
 // Returns whether ARC can run on the filesystem mounted at |path|.
 // This function should run only on threads where IO operations are allowed.
 bool IsArcCompatibleFilesystem(const base::FilePath& path) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   // If it can be verified it is not on ecryptfs, then it is ok.
   struct statfs statfs_buf;
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
index 8ae48038..0f2c45c 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
@@ -11,7 +11,7 @@
 
 #include "base/files/file.h"
 #include "base/task/post_task.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/chromeos/arc/fileapi/arc_file_system_operation_runner_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "mojo/public/cpp/platform/platform_handle.h"
@@ -32,7 +32,7 @@
 
 // Seeks the file, returns 0 on success, or errno on an error.
 int SeekFile(base::File* file, size_t offset) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   // lseek() instead of |file|'s method for errno.
   off_t result = lseek(file->GetPlatformFile(), offset, SEEK_SET);
   return result < 0 ? errno : 0;
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
index e27c3623..6d4236c1 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -905,9 +905,9 @@
     NOTREACHED();
     return;
   }
-  linked_ptr<drive::FileChange> changes;
+  std::unique_ptr<drive::FileChange> changes;
   if (list)
-    changes.reset(new drive::FileChange(*list));  // Copy
+    changes = std::make_unique<drive::FileChange>(*list);  // Copy
 
   for (size_t i = 0; i < extension_ids.size(); ++i) {
     std::string* extension_id = new std::string(extension_ids[i]);
@@ -922,13 +922,13 @@
         profile_, *extension_id, file_definition,
         base::BindOnce(
             &EventRouter::DispatchDirectoryChangeEventWithEntryDefinition,
-            weak_factory_.GetWeakPtr(), changes, base::Owned(extension_id),
-            got_error));
+            weak_factory_.GetWeakPtr(), std::move(changes),
+            base::Owned(extension_id), got_error));
   }
 }
 
 void EventRouter::DispatchDirectoryChangeEventWithEntryDefinition(
-    const linked_ptr<drive::FileChange> list,
+    std::unique_ptr<drive::FileChange> list,
     const std::string* extension_id,
     bool watcher_error,
     const EntryDefinition& entry_definition) {
@@ -946,7 +946,7 @@
       : file_manager_private::FILE_WATCH_EVENT_TYPE_CHANGED;
 
   // Detailed information is available.
-  if (list.get()) {
+  if (list) {
     event.changed_files =
         std::make_unique<std::vector<file_manager_private::FileChange>>();
 
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h
index ab63ed2d..f18b2e7 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.h
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -180,7 +180,7 @@
   // Sends directory change event, after converting the file definition to entry
   // definition.
   void DispatchDirectoryChangeEventWithEntryDefinition(
-      const linked_ptr<drive::FileChange> list,
+      std::unique_ptr<drive::FileChange> list,
       const std::string* extension_id,
       bool watcher_error,
       const EntryDefinition& entry_definition);
diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
index 2f33cbb..f44699b 100644
--- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
+++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
@@ -9,7 +9,6 @@
 #include <memory>
 #include <utility>
 
-#include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/services/filesystem/public/interfaces/types.mojom.h"
 #include "net/base/io_buffer.h"
@@ -73,7 +72,7 @@
   metadata->mime_type.reset(new std::string(mime_type));
 
   entries_[entry_path] =
-      make_linked_ptr(new FakeEntry(std::move(metadata), contents));
+      std::make_unique<FakeEntry>(std::move(metadata), contents);
 }
 
 const FakeEntry* FakeProvidedFileSystem::GetEntry(
@@ -98,10 +97,8 @@
   const Entries::const_iterator entry_it = entries_.find(entry_path);
 
   if (entry_it == entries_.end()) {
-    return PostAbortableTask(
-        base::BindOnce(std::move(callback),
-                       base::Passed(base::WrapUnique<EntryMetadata>(NULL)),
-                       base::File::FILE_ERROR_NOT_FOUND));
+    return PostAbortableTask(base::BindOnce(std::move(callback), nullptr,
+                                            base::File::FILE_ERROR_NOT_FOUND));
   }
 
   std::unique_ptr<EntryMetadata> metadata(new EntryMetadata);
diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h
index 4d6921bc..70df78ae 100644
--- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h
+++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.h
@@ -8,13 +8,13 @@
 #include <stdint.h>
 
 #include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/callback.h"
 #include "base/files/file.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/task/cancelable_task_tracker.h"
@@ -163,7 +163,7 @@
   base::WeakPtr<ProvidedFileSystemInterface> GetWeakPtr() override;
 
  private:
-  typedef std::map<base::FilePath, linked_ptr<FakeEntry>> Entries;
+  using Entries = std::map<base::FilePath, std::unique_ptr<FakeEntry>>;
 
   // Utility function for posting a task which can be aborted by calling the
   // returned callback.
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index cc3c959d..42e5e3c 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -393,10 +393,11 @@
   UserImageManagerMap::iterator ui = user_image_managers_.find(account_id);
   if (ui != user_image_managers_.end())
     return ui->second.get();
-  linked_ptr<UserImageManagerImpl> mgr(
-      new UserImageManagerImpl(account_id.GetUserEmail(), this));
-  user_image_managers_[account_id] = mgr;
-  return mgr.get();
+  auto mgr =
+      std::make_unique<UserImageManagerImpl>(account_id.GetUserEmail(), this);
+  UserImageManagerImpl* mgr_raw = mgr.get();
+  user_image_managers_[account_id] = std::move(mgr);
+  return mgr_raw;
 }
 
 SupervisedUserManager* ChromeUserManagerImpl::GetSupervisedUserManager() {
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
index 99929993..dbee25b 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
@@ -12,7 +12,6 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/synchronization/lock.h"
@@ -197,7 +196,8 @@
   friend class WallpaperManager;
   friend class WallpaperManagerTest;
 
-  using UserImageManagerMap = std::map<AccountId, linked_ptr<UserImageManager>>;
+  using UserImageManagerMap =
+      std::map<AccountId, std::unique_ptr<UserImageManager>>;
 
   ChromeUserManagerImpl();
 
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 26296978..7773c32 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -1350,7 +1350,8 @@
     return;
 
   // First remember how far have we reached so that we can resume if needed.
-  if (is_out_of_box_ && IsResumableScreen(current_screen_->screen_id())) {
+  if (is_out_of_box_ && !demo_setup_controller_ &&
+      IsResumableScreen(current_screen_->screen_id())) {
     StartupUtils::SaveOobePendingScreen(
         GetOobeScreenName(current_screen_->screen_id()));
   }
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index 834ab41..474fb71 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -12,7 +12,6 @@
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/optional.h"
diff --git a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc
index 8b26041..7bd39fd 100644
--- a/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/ownership/owner_settings_service_chromeos_unittest.cc
@@ -9,7 +9,6 @@
 
 #include "base/containers/queue.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/run_loop.h"
 #include "base/test/scoped_path_override.h"
 #include "base/values.h"
@@ -50,10 +49,10 @@
       return;
 
     while (!set_requests_.empty()) {
-      SetRequest request = set_requests_.front();
+      SetRequest request = std::move(set_requests_.front());
       set_requests_.pop();
       const base::Value* value = provider_->Get(request.first);
-      ASSERT_TRUE(request.second->Equals(value));
+      ASSERT_EQ(request.second, *value);
     }
     loop_.Quit();
   }
@@ -61,8 +60,7 @@
   bool Set(const std::string& setting, const base::Value& value) {
     if (!service_->Set(setting, value))
       return false;
-    set_requests_.push(
-        SetRequest(setting, linked_ptr<base::Value>(value.DeepCopy())));
+    set_requests_.push(SetRequest(setting, value.Clone()));
     return true;
   }
 
@@ -73,7 +71,7 @@
   DeviceSettingsProvider* provider_;
   base::RunLoop loop_;
 
-  using SetRequest = std::pair<std::string, linked_ptr<base::Value>>;
+  using SetRequest = std::pair<std::string, base::Value>;
   base::queue<SetRequest> set_requests_;
 
   DISALLOW_COPY_AND_ASSIGN(PrefsChecker);
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
index e7e57b2..02974f7 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.cc
@@ -741,7 +741,7 @@
 }
 
 void PlatformKeysService::StartOrQueueTask(std::unique_ptr<Task> task) {
-  tasks_.push(make_linked_ptr(task.release()));
+  tasks_.push(std::move(task));
   if (tasks_.size() == 1)
     tasks_.front()->Start();
 }
diff --git a/chrome/browser/chromeos/platform_keys/platform_keys_service.h b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
index b77be3d..17045fa 100644
--- a/chrome/browser/chromeos/platform_keys/platform_keys_service.h
+++ b/chrome/browser/chromeos/platform_keys/platform_keys_service.h
@@ -12,7 +12,6 @@
 #include "base/callback_forward.h"
 #include "base/containers/queue.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/platform_keys/key_permissions.h"
 #include "chrome/browser/chromeos/platform_keys/platform_keys.h"
@@ -205,7 +204,7 @@
   content::BrowserContext* browser_context_;
   KeyPermissions key_permissions_;
   std::unique_ptr<SelectDelegate> select_delegate_;
-  base::queue<linked_ptr<Task>> tasks_;
+  base::queue<std::unique_ptr<Task>> tasks_;
   base::WeakPtrFactory<PlatformKeysService> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(PlatformKeysService);
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc
index 778e91c..eb831deb 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc
+++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.cc
@@ -176,10 +176,8 @@
 
   ProfilePolicyConnector* policy_connector =
       ProfilePolicyConnectorFactory::GetForBrowserContext(profile);
-  logged_in_user_observers_[user_id] = make_linked_ptr(
-      new PolicyServiceObserver(this,
-                                user_id,
-                                policy_connector->policy_service()));
+  logged_in_user_observers_[user_id] = std::make_unique<PolicyServiceObserver>(
+      this, user_id, policy_connector->policy_service());
 }
 
 void CloudExternalDataPolicyObserver::OnPolicyUpdated(
@@ -282,7 +280,7 @@
 
   delegate_->OnExternalDataSet(policy_, user_id);
 
-  linked_ptr<WeakPtrFactory>& weak_ptr_factory = fetch_weak_ptrs_[user_id];
+  std::unique_ptr<WeakPtrFactory>& weak_ptr_factory = fetch_weak_ptrs_[user_id];
   weak_ptr_factory.reset(new WeakPtrFactory(this));
   if (entry->external_data_fetcher) {
     entry->external_data_fetcher->Fetch(base::Bind(
diff --git a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h
index aef0b8d5..ef4467b8 100644
--- a/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h
+++ b/chrome/browser/chromeos/policy/cloud_external_data_policy_observer.h
@@ -11,7 +11,6 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
@@ -100,8 +99,8 @@
 
   // A map from each logged-in user to the helper that observes |policy_| in the
   // user's PolicyService.
-  typedef std::map<std::string, linked_ptr<PolicyServiceObserver>>
-      LoggedInUserObserverMap;
+  using LoggedInUserObserverMap =
+      std::map<std::string, std::unique_ptr<PolicyServiceObserver>>;
   LoggedInUserObserverMap logged_in_user_observers_;
 
   chromeos::CrosSettings* cros_settings_;
@@ -120,7 +119,8 @@
   // currently in progress. This allows fetches to be effectively be canceled by
   // invalidating the pointers.
   using WeakPtrFactory = base::WeakPtrFactory<CloudExternalDataPolicyObserver>;
-  using FetchWeakPtrMap = std::map<std::string, linked_ptr<WeakPtrFactory>>;
+  using FetchWeakPtrMap =
+      std::map<std::string, std::unique_ptr<WeakPtrFactory>>;
   FetchWeakPtrMap fetch_weak_ptrs_;
 
   base::WeakPtrFactory<CloudExternalDataPolicyObserver> weak_factory_;
diff --git a/chrome/browser/chromeos/settings/device_settings_service.cc b/chrome/browser/chromeos/settings/device_settings_service.cc
index 4e2229e..278656b 100644
--- a/chrome/browser/chromeos/settings/device_settings_service.cc
+++ b/chrome/browser/chromeos/settings/device_settings_service.cc
@@ -143,10 +143,10 @@
     const base::Closure& callback) {
   // On Active Directory managed devices policy is written only by authpolicyd.
   CHECK(device_mode_ != policy::DEVICE_MODE_ENTERPRISE_AD);
-  Enqueue(linked_ptr<SessionManagerOperation>(new StoreSettingsOperation(
+  Enqueue(std::make_unique<StoreSettingsOperation>(
       base::Bind(&DeviceSettingsService::HandleCompletedAsyncOperation,
                  weak_factory_.GetWeakPtr(), callback),
-      std::move(policy))));
+      std::move(policy)));
 }
 
 DeviceSettingsService::OwnershipStatus
@@ -243,9 +243,10 @@
 }
 
 void DeviceSettingsService::Enqueue(
-    const linked_ptr<SessionManagerOperation>& operation) {
-  pending_operations_.push_back(operation);
-  if (pending_operations_.front().get() == operation.get())
+    std::unique_ptr<SessionManagerOperation> operation) {
+  const bool was_empty = pending_operations_.empty();
+  pending_operations_.push_back(std::move(operation));
+  if (was_empty)
     StartNextOperation();
 }
 
@@ -255,11 +256,10 @@
     request_key_load = false;
     cloud_validations = false;
   }
-  linked_ptr<SessionManagerOperation> operation(new LoadSettingsOperation(
+  Enqueue(std::make_unique<LoadSettingsOperation>(
       request_key_load, cloud_validations, false /*force_immediate_load*/,
       base::Bind(&DeviceSettingsService::HandleCompletedAsyncOperation,
                  weak_factory_.GetWeakPtr(), base::Closure())));
-  Enqueue(operation);
 }
 
 void DeviceSettingsService::EnsureReload(bool request_key_load) {
diff --git a/chrome/browser/chromeos/settings/device_settings_service.h b/chrome/browser/chromeos/settings/device_settings_service.h
index 2718b9d..9ee38b14 100644
--- a/chrome/browser/chromeos/settings/device_settings_service.h
+++ b/chrome/browser/chromeos/settings/device_settings_service.h
@@ -13,7 +13,6 @@
 #include "base/compiler_specific.h"
 #include "base/containers/circular_deque.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
 #include "chromeos/dbus/session_manager_client.h"
@@ -210,7 +209,7 @@
 
   // Enqueues a new operation. Takes ownership of |operation| and starts it
   // right away if there is no active operation currently.
-  void Enqueue(const linked_ptr<SessionManagerOperation>& operation);
+  void Enqueue(std::unique_ptr<SessionManagerOperation> operation);
 
   // Enqueues a load operation.
   void EnqueueLoad(bool request_key_load);
@@ -263,7 +262,8 @@
 
   // The queue of pending operations. The first operation on the queue is
   // currently active; it gets removed and destroyed once it completes.
-  base::circular_deque<linked_ptr<SessionManagerOperation>> pending_operations_;
+  base::circular_deque<std::unique_ptr<SessionManagerOperation>>
+      pending_operations_;
 
   base::ObserverList<Observer>::Unchecked observers_;
 
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.h b/chrome/browser/chromeos/smb_client/smb_file_system.h
index 7050839..528c5df 100644
--- a/chrome/browser/chromeos/smb_client/smb_file_system.h
+++ b/chrome/browser/chromeos/smb_client/smb_file_system.h
@@ -14,7 +14,6 @@
 #include "base/callback.h"
 #include "base/files/file.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/timer/elapsed_timer.h"
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
index b78a02e..643c19c 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.cc
@@ -305,3 +305,11 @@
   }
   remote_locations_.swap(remote_locations);
 }
+
+void ChromeDevToolsManagerDelegate::ResetAndroidDeviceManagerForTesting() {
+  device_manager_.reset();
+
+  // We also need |device_discovery_| to go away because there may be a pending
+  // task using a raw pointer to the DeviceManager we just deleted.
+  device_discovery_.reset();
+}
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.h b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
index f5ac9d7b..3f490b4 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.h
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
@@ -46,6 +46,9 @@
   static bool AllowInspection(Profile* profile,
                               const extensions::Extension* extension);
 
+  // Resets |device_manager_|.
+  void ResetAndroidDeviceManagerForTesting();
+
  private:
   friend class DevToolsManagerDelegateTest;
 
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.cc b/chrome/browser/devtools/device/devtools_android_bridge.cc
index 9007e47..db3f446 100644
--- a/chrome/browser/devtools/device/devtools_android_bridge.cc
+++ b/chrome/browser/devtools/device/devtools_android_bridge.cc
@@ -98,6 +98,11 @@
   return new DevToolsAndroidBridge(profile);
 }
 
+void DevToolsAndroidBridge::Shutdown() {
+  // Needed for Chrome_DevToolsADBThread to shut down gracefully in tests.
+  device_manager_.reset();
+}
+
 scoped_refptr<content::DevToolsAgentHost>
 DevToolsAndroidBridge::GetBrowserAgentHost(
     scoped_refptr<RemoteBrowser> browser) {
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.h b/chrome/browser/devtools/device/devtools_android_bridge.h
index 2b737b74..b59161c 100644
--- a/chrome/browser/devtools/device/devtools_android_bridge.h
+++ b/chrome/browser/devtools/device/devtools_android_bridge.h
@@ -134,6 +134,8 @@
       base::Callback<void(scoped_refptr<TCPDeviceProvider>)>;
   void set_tcp_provider_callback_for_test(TCPProviderCallback callback);
 
+  void Shutdown() override;
+
  private:
   friend struct content::BrowserThread::DeleteOnThread<
       content::BrowserThread::UI>;
@@ -162,7 +164,7 @@
   }
 
   Profile* const profile_;
-  const std::unique_ptr<AndroidDeviceManager> device_manager_;
+  std::unique_ptr<AndroidDeviceManager> device_manager_;
 
   using DeviceMap =
       std::map<std::string, scoped_refptr<AndroidDeviceManager::Device> >;
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index b916faf..0e28dbe1 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -2237,6 +2237,8 @@
         base::StringPrintf("while testing URL: %s", pair.first.c_str()));
     EXPECT_EQ(opened_url, pair.second);
   }
+
+  CloseDevToolsWindow();
 }
 
 IN_PROC_BROWSER_TEST_F(DevToolsSanityTest, LoadNetworkResourceForFrontend) {
diff --git a/chrome/browser/devtools/devtools_window_testing.cc b/chrome/browser/devtools/devtools_window_testing.cc
index 50e0095..c0c99ff 100644
--- a/chrome/browser/devtools/devtools_window_testing.cc
+++ b/chrome/browser/devtools/devtools_window_testing.cc
@@ -6,6 +6,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/devtools/chrome_devtools_manager_delegate.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -43,6 +44,10 @@
     close_callback_.Run();
     close_callback_ = base::Closure();
   }
+
+  // Needed for Chrome_DevToolsADBThread to shut down gracefully in tests.
+  ChromeDevToolsManagerDelegate::GetInstance()
+      ->ResetAndroidDeviceManagerForTesting();
 }
 
 // static
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 13bdd29e..1f674f0 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -3730,19 +3730,19 @@
       fake_metadata.download_request().SerializeAsString());
   std::string ping_response(
       fake_metadata.download_response().SerializeAsString());
-  safe_browsing::SafeBrowsingService* sb_service =
-      g_browser_process->safe_browsing_service();
-  safe_browsing::DownloadProtectionService* download_protection_service =
-      sb_service->download_protection_service();
-  download_protection_service->feedback_service()->MaybeStorePingsForDownload(
+  safe_browsing::DownloadFeedbackService::MaybeStorePingsForDownload(
       safe_browsing::DownloadCheckResult::UNCOMMON, true /* upload_requested */,
       downloads[0], ping_request, ping_response);
   ASSERT_TRUE(safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
       *(downloads[0])));
 
   // Begin feedback and check that the file is "stolen".
-  download_protection_service->feedback_service()->BeginFeedbackForDownload(
-      downloads[0], DownloadCommands::DISCARD);
+  safe_browsing::SafeBrowsingService* sb_service =
+      g_browser_process->safe_browsing_service();
+  safe_browsing::DownloadProtectionService* download_protection_service =
+      sb_service->download_protection_service();
+  download_protection_service->MaybeBeginFeedbackForDownload(
+      browser()->profile(), downloads[0], DownloadCommands::DISCARD);
   std::vector<DownloadItem*> updated_downloads;
   GetDownloads(browser(), &updated_downloads);
   ASSERT_TRUE(updated_downloads.empty());
@@ -3789,19 +3789,19 @@
       fake_metadata.download_request().SerializeAsString());
   std::string ping_response(
       fake_metadata.download_response().SerializeAsString());
-  safe_browsing::SafeBrowsingService* sb_service =
-      g_browser_process->safe_browsing_service();
-  safe_browsing::DownloadProtectionService* download_protection_service =
-      sb_service->download_protection_service();
-  download_protection_service->feedback_service()->MaybeStorePingsForDownload(
+  safe_browsing::DownloadFeedbackService::MaybeStorePingsForDownload(
       safe_browsing::DownloadCheckResult::UNCOMMON, true /* upload_requested */,
       downloads[0], ping_request, ping_response);
   ASSERT_TRUE(safe_browsing::DownloadFeedbackService::IsEnabledForDownload(
       *(downloads[0])));
 
   // Begin feedback and check that file is still there.
-  download_protection_service->feedback_service()->BeginFeedbackForDownload(
-      downloads[0], DownloadCommands::KEEP);
+  safe_browsing::SafeBrowsingService* sb_service =
+      g_browser_process->safe_browsing_service();
+  safe_browsing::DownloadProtectionService* download_protection_service =
+      sb_service->download_protection_service();
+  download_protection_service->MaybeBeginFeedbackForDownload(
+      browser()->profile(), downloads[0], DownloadCommands::KEEP);
   completion_observer->WaitForFinished();
 
   std::vector<DownloadItem*> updated_downloads;
diff --git a/chrome/browser/download/download_started_animation.h b/chrome/browser/download/download_started_animation.h
index 250302b..fe31baf 100644
--- a/chrome/browser/download/download_started_animation.h
+++ b/chrome/browser/download/download_started_animation.h
@@ -6,7 +6,6 @@
 #define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_STARTED_ANIMATION_H_
 
 #include "base/macros.h"
-#include "build/build_config.h"
 
 namespace content {
 class WebContents;
@@ -15,11 +14,6 @@
 class DownloadStartedAnimation {
  public:
   static void Show(content::WebContents* web_contents);
-#if defined(OS_MACOSX)
-  // Temporary shim for Polychrome. See bottom of first comment in
-  // https://crbug.com/804950 for details
-  static void ShowCocoa(content::WebContents* web_contents);
-#endif
 
  private:
   DownloadStartedAnimation() { }
diff --git a/chrome/browser/extensions/api/debugger/debugger_api.cc b/chrome/browser/extensions/api/debugger/debugger_api.cc
index 7c7a602..a7c4849 100644
--- a/chrome/browser/extensions/api/debugger/debugger_api.cc
+++ b/chrome/browser/extensions/api/debugger/debugger_api.cc
@@ -369,9 +369,8 @@
   const GURL& site_instance_url =
       render_frame_host->GetSiteInstance()->GetSiteURL();
 
-  if (site_instance_url.is_empty()) {
-    // |site_instance_url| is empty for about:blank. Allow the extension to
-    // attach.
+  if (site_instance_url.is_empty() || site_instance_url == "about:") {
+    // Allow the extension to attach to about:blank.
     return true;
   }
 
diff --git a/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
index ea51782..e50a7b2 100644
--- a/chrome/browser/extensions/api/sessions/sessions_apitest.cc
+++ b/chrome/browser/extensions/api/sessions/sessions_apitest.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/sync/chrome_sync_client.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/profile_sync_test_util.h"
+#include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -35,6 +36,7 @@
 #include "components/sync/model/data_type_activation_request.h"
 #include "components/sync/test/engine/mock_model_type_worker.h"
 #include "components/sync_sessions/session_store.h"
+#include "components/sync_sessions/session_sync_service.h"
 #include "extensions/browser/api_test_utils.h"
 #include "extensions/common/extension_builder.h"
 
@@ -268,8 +270,8 @@
 
   std::unique_ptr<syncer::DataTypeActivationResponse> activation_response;
   base::RunLoop loop;
-  ProfileSyncServiceFactory::GetForProfile(browser_->profile())
-      ->GetSessionSyncControllerDelegate()
+  SessionSyncServiceFactory::GetForProfile(browser_->profile())
+      ->GetControllerDelegate()
       ->OnSyncStarting(
           request, base::BindLambdaForTesting(
                        [&](std::unique_ptr<syncer::DataTypeActivationResponse>
diff --git a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
index 71928f9f..ff1a5e0 100644
--- a/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
+++ b/chrome/browser/extensions/extension_garbage_collector_chromeos_unittest.cc
@@ -33,7 +33,6 @@
 #include "extensions/browser/extension_prefs.h"
 #include "extensions/browser/install_flag.h"
 #include "extensions/common/extension_builder.h"
-#include "extensions/common/manifest_constants.h"
 #include "extensions/common/value_builder.h"
 #include "ppapi/buildflags/buildflags.h"
 
@@ -121,7 +120,7 @@
                                            const std::string& version,
                                            const base::FilePath& path) {
     return ExtensionBuilder("test")
-        .SetManifestKey(manifest_keys::kVersion, version)
+        .SetVersion(version)
         .SetID(id)
         .SetPath(path)
         .SetLocation(Manifest::INTERNAL)
diff --git a/chrome/browser/extensions/extension_loading_browsertest.cc b/chrome/browser/extensions/extension_loading_browsertest.cc
index f782779..22d79dd 100644
--- a/chrome/browser/extensions/extension_loading_browsertest.cc
+++ b/chrome/browser/extensions/extension_loading_browsertest.cc
@@ -9,6 +9,8 @@
 #include "base/strings/stringprintf.h"
 #include "base/version.h"
 #include "build/build_config.h"
+#include "chrome/browser/devtools/devtools_window.h"
+#include "chrome/browser/devtools/devtools_window_testing.h"
 #include "chrome/browser/extensions/devtools_util.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -304,6 +306,11 @@
   ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
       bg_contents, "domAutomationController.send(is_valid);", &is_valid));
   EXPECT_TRUE(is_valid);
+
+  // Tidy up.
+  DevToolsWindowTesting::CloseDevToolsWindowSync(
+      DevToolsWindow::FindDevToolsWindow(
+          content::DevToolsAgentHost::GetOrCreateFor(bg_contents).get()));
 }
 
 }  // namespace
diff --git a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
index d1a1a77..15b701f 100644
--- a/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
+++ b/chrome/browser/media_galleries/chromeos/mtp_device_delegate_impl_chromeos.cc
@@ -25,7 +25,7 @@
 #include "base/strings/string_util.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/media_galleries/chromeos/mtp_device_task_helper_map_service.h"
 #include "chrome/browser/media_galleries/chromeos/snapshot_file_details.h"
 #include "components/services/filesystem/public/interfaces/types.mojom.h"
@@ -356,7 +356,7 @@
 std::pair<int, base::File::Error> OpenFileDescriptor(
     const base::FilePath& file_path,
     const int flags) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   if (base::DirectoryExists(file_path))
     return std::make_pair(-1, base::File::FILE_ERROR_NOT_A_FILE);
@@ -370,7 +370,7 @@
 
 // Closes |file_descriptor| on a background task runner.
 void CloseFileDescriptor(const int file_descriptor) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   IGNORE_EINTR(close(file_descriptor));
 }
diff --git a/chrome/browser/media_galleries/chromeos/mtp_read_file_worker.cc b/chrome/browser/media_galleries/chromeos/mtp_read_file_worker.cc
index a1bb63c..37c1f20 100644
--- a/chrome/browser/media_galleries/chromeos/mtp_read_file_worker.cc
+++ b/chrome/browser/media_galleries/chromeos/mtp_read_file_worker.cc
@@ -12,7 +12,6 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
-#include "base/threading/thread_restrictions.h"
 #include "chrome/browser/media_galleries/chromeos/snapshot_file_details.h"
 #include "components/storage_monitor/storage_monitor.h"
 #include "content/public/browser/browser_task_traits.h"
@@ -30,7 +29,6 @@
 uint32_t WriteDataChunkIntoSnapshotFileOnFileThread(
     const base::FilePath& snapshot_file_path,
     const std::string& data) {
-  base::AssertBlockingAllowed();
   return base::AppendToFile(snapshot_file_path, data.c_str(), data.size())
              ? base::checked_cast<uint32_t>(data.size())
              : 0;
diff --git a/chrome/browser/media_galleries/gallery_watch_manager.cc b/chrome/browser/media_galleries/gallery_watch_manager.cc
index ddb55c7..42b81de 100644
--- a/chrome/browser/media_galleries/gallery_watch_manager.cc
+++ b/chrome/browser/media_galleries/gallery_watch_manager.cc
@@ -15,7 +15,7 @@
 #include "base/stl_util.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media_galleries/gallery_watch_manager_observer.h"
@@ -118,7 +118,7 @@
     const base::FilePath& path,
     const base::Callback<void(bool)>& callback) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   // This can occur if the GalleryWatchManager attempts to watch the same path
   // again before recieving the callback. It's benign.
@@ -144,7 +144,6 @@
 void GalleryWatchManager::FileWatchManager::RemoveFileWatch(
     const base::FilePath& path) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::AssertBlockingAllowed();
 
   size_t erased = watchers_.erase(path);
   DCHECK_EQ(erased, 1u);
@@ -159,7 +158,6 @@
     const base::FilePath& path,
     bool error) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  base::AssertBlockingAllowed();
 
   if (error)
     RemoveFileWatch(path);
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
index 98713b0..c79f0b2 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -23,7 +23,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/task_runner_util.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
 #include "chrome/browser/media_galleries/win/mtp_device_object_entry.h"
 #include "chrome/browser/media_galleries/win/mtp_device_object_enumerator.h"
@@ -70,7 +70,6 @@
 base::string16 GetFileObjectIdFromPathOnBlockingPoolThread(
     const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info,
     const base::FilePath& file_path) {
-  base::AssertBlockingAllowed();
   DCHECK(!file_path.empty());
   IPortableDevice* device =
       PortableDeviceMapService::GetInstance()->GetPortableDevice(
@@ -108,7 +107,6 @@
 CreateFileEnumeratorOnBlockingPoolThread(
     const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info,
     const base::FilePath& root) {
-  base::AssertBlockingAllowed();
   DCHECK(!device_info.registered_device_path.empty());
   DCHECK(!root.empty());
   IPortableDevice* device =
@@ -139,7 +137,6 @@
 bool OpenDeviceOnBlockingPoolThread(
     const base::string16& pnp_device_id,
     const base::string16& registered_device_path) {
-  base::AssertBlockingAllowed();
   DCHECK(!pnp_device_id.empty());
   DCHECK(!registered_device_path.empty());
   Microsoft::WRL::ComPtr<IPortableDevice> device =
@@ -160,7 +157,6 @@
     const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info,
     const base::FilePath& file_path,
     base::File::Info* file_info) {
-  base::AssertBlockingAllowed();
   DCHECK(!device_info.registered_device_path.empty());
   DCHECK(!file_path.empty());
   DCHECK(file_info);
@@ -186,7 +182,7 @@
     const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info,
     const base::FilePath& root,
     storage::AsyncFileUtil::EntryList* entries) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(!root.empty());
   DCHECK(entries);
   base::File::Info file_info;
@@ -221,7 +217,6 @@
 base::File::Error GetFileStreamOnBlockingPoolThread(
     const MTPDeviceDelegateImplWin::StorageDeviceInfo& device_info,
     SnapshotFileDetails* file_details) {
-  base::AssertBlockingAllowed();
   DCHECK(file_details);
   DCHECK(!file_details->request_info().device_file_path.empty());
   DCHECK(!file_details->request_info().snapshot_file_path.empty());
@@ -278,7 +273,6 @@
 // files, or 0 on failure. For empty files, just return 0.
 DWORD WriteDataChunkIntoSnapshotFileOnBlockingPoolThread(
     const SnapshotFileDetails& file_details) {
-  base::AssertBlockingAllowed();
   if (file_details.file_info().size == 0)
     return 0;
   return media_transfer_protocol::CopyDataChunkToLocalFile(
@@ -289,7 +283,6 @@
 
 void DeletePortableDeviceOnBlockingPoolThread(
     const base::string16& registered_device_path) {
-  base::AssertBlockingAllowed();
   PortableDeviceMapService::GetInstance()->RemovePortableDevice(
       registered_device_path);
 }
diff --git a/chrome/browser/media_galleries/win/mtp_device_object_enumerator.cc b/chrome/browser/media_galleries/win/mtp_device_object_enumerator.cc
index 5052e62..52e5154 100644
--- a/chrome/browser/media_galleries/win/mtp_device_object_enumerator.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_object_enumerator.cc
@@ -7,15 +7,10 @@
 #include "chrome/browser/media_galleries/win/mtp_device_object_enumerator.h"
 
 #include "base/logging.h"
-#include "base/threading/thread_restrictions.h"
 
 MTPDeviceObjectEnumerator::MTPDeviceObjectEnumerator(
     const MTPDeviceObjectEntries& entries)
-    : object_entries_(entries),
-      index_(0U),
-      is_index_ready_(false) {
-  base::AssertBlockingAllowed();
-}
+    : object_entries_(entries), index_(0U), is_index_ready_(false) {}
 
 MTPDeviceObjectEnumerator::~MTPDeviceObjectEnumerator() {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chrome/browser/media_galleries/win/mtp_device_operations_util.cc b/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
index 99861c5..f9ee8f3 100644
--- a/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_operations_util.cc
@@ -17,7 +17,7 @@
 #include "base/logging.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_util.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/time/time.h"
 #include "base/win/scoped_co_mem.h"
 #include "base/win/scoped_propvariant.h"
@@ -32,7 +32,7 @@
 // application that communicates with the device.
 bool GetClientInformation(
     Microsoft::WRL::ComPtr<IPortableDeviceValues>* client_info) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(client_info);
   HRESULT hr = ::CoCreateInstance(__uuidof(PortableDeviceValues), NULL,
                                   CLSCTX_INPROC_SERVER,
@@ -58,7 +58,7 @@
 // the IPortableDeviceContent interface. On failure, returns NULL.
 Microsoft::WRL::ComPtr<IPortableDeviceContent> GetDeviceContent(
     IPortableDevice* device) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(device);
   Microsoft::WRL::ComPtr<IPortableDeviceContent> content;
   if (SUCCEEDED(device->Content(content.GetAddressOf())))
@@ -72,7 +72,7 @@
 Microsoft::WRL::ComPtr<IEnumPortableDeviceObjectIDs> GetDeviceObjectEnumerator(
     IPortableDevice* device,
     const base::string16& parent_id) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(device);
   DCHECK(!parent_id.empty());
   Microsoft::WRL::ComPtr<IPortableDeviceContent> content =
@@ -175,7 +175,7 @@
                       bool* is_directory,
                       int64_t* size,
                       base::Time* last_modified_time) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(device);
   DCHECK(!object_id.empty());
   DCHECK(name);
@@ -241,7 +241,7 @@
 // On success, returns true and fills in |entry|.
 MTPDeviceObjectEntry GetMTPDeviceObjectEntry(IPortableDevice* device,
                                              const base::string16& object_id) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(device);
   DCHECK(!object_id.empty());
   base::string16 name;
@@ -265,7 +265,7 @@
                                const base::string16& directory_object_id,
                                const base::string16& object_name,
                                MTPDeviceObjectEntries* object_entries) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(device);
   DCHECK(!directory_object_id.empty());
   DCHECK(object_entries);
@@ -306,7 +306,7 @@
 
 Microsoft::WRL::ComPtr<IPortableDevice> OpenDevice(
     const base::string16& pnp_device_id) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(!pnp_device_id.empty());
   Microsoft::WRL::ComPtr<IPortableDeviceValues> client_info;
   if (!GetClientInformation(&client_info))
@@ -356,7 +356,7 @@
                                const base::string16& file_object_id,
                                IStream** file_stream,
                                DWORD* optimal_transfer_size) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(device);
   DCHECK(!file_object_id.empty());
   Microsoft::WRL::ComPtr<IPortableDeviceContent> content =
@@ -376,7 +376,7 @@
 DWORD CopyDataChunkToLocalFile(IStream* stream,
                                const base::FilePath& local_path,
                                size_t optimal_transfer_size) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(stream);
   DCHECK(!local_path.empty());
   if (optimal_transfer_size == 0U)
diff --git a/chrome/browser/media_galleries/win/portable_device_map_service.cc b/chrome/browser/media_galleries/win/portable_device_map_service.cc
index 6020503..e5a16fb1 100644
--- a/chrome/browser/media_galleries/win/portable_device_map_service.cc
+++ b/chrome/browser/media_galleries/win/portable_device_map_service.cc
@@ -6,7 +6,6 @@
 
 #include "base/logging.h"
 #include "base/stl_util.h"
-#include "base/threading/thread_restrictions.h"
 #include "content/public/browser/browser_thread.h"
 
 namespace {
@@ -24,7 +23,6 @@
 void PortableDeviceMapService::AddPortableDevice(
     const base::string16& device_location,
     IPortableDevice* device) {
-  base::AssertBlockingAllowed();
   DCHECK(!device_location.empty());
   DCHECK(device);
   base::AutoLock lock(lock_);
@@ -43,7 +41,6 @@
 
 void PortableDeviceMapService::RemovePortableDevice(
     const base::string16& device_location) {
-  base::AssertBlockingAllowed();
   DCHECK(!device_location.empty());
   base::AutoLock lock(lock_);
   PortableDeviceMap::const_iterator it = device_map_.find(device_location);
@@ -53,7 +50,6 @@
 
 IPortableDevice* PortableDeviceMapService::GetPortableDevice(
     const base::string16& device_location) {
-  base::AssertBlockingAllowed();
   DCHECK(!device_location.empty());
   base::AutoLock lock(lock_);
   PortableDeviceMap::const_iterator it = device_map_.find(device_location);
diff --git a/chrome/browser/notifications/OWNERS b/chrome/browser/notifications/OWNERS
index 82f60d8f..8d106f95 100644
--- a/chrome/browser/notifications/OWNERS
+++ b/chrome/browser/notifications/OWNERS
@@ -9,6 +9,7 @@
 per-file *_mac*=rsesek@chromium.org
 
 # Windows files
+per-file *_win*=chengx@chromium.org
 per-file *_win*=finnur@chromium.org
 
 per-file *permission_context*=file://chrome/browser/permissions/PERMISSIONS_OWNERS
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc
index b642c8a..9a9cd9a 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win.cc
@@ -155,14 +155,11 @@
   // NotificationTemplateBuilder). This function is only used when displaying
   // notification in production code, which explains why the UMA metrics record
   // within are classified with the display path.
-  HRESULT GetToastNotification(
+  mswr::ComPtr<winui::Notifications::IToastNotification> GetToastNotification(
       const message_center::Notification& notification,
       const NotificationTemplateBuilder& notification_template_builder,
       const std::string& profile_id,
-      bool incognito,
-      winui::Notifications::IToastNotification** toast_notification) {
-    *toast_notification = nullptr;
-
+      bool incognito) {
     ScopedHString ref_class_name =
         ScopedHString::Create(RuntimeClass_Windows_Data_Xml_Dom_XmlDocument);
     mswr::ComPtr<IInspectable> inspectable;
@@ -171,7 +168,7 @@
     if (FAILED(hr)) {
       LogDisplayHistogram(DisplayStatus::RO_ACTIVATE_FAILED);
       DLOG(ERROR) << "Unable to activate the XML Document " << std::hex << hr;
-      return hr;
+      return nullptr;
     }
 
     mswr::ComPtr<winxml::Dom::IXmlDocumentIO> document_io;
@@ -181,7 +178,7 @@
           DisplayStatus::CONVERSION_FAILED_INSPECTABLE_TO_XML_IO);
       DLOG(ERROR) << "Failed to get XmlDocument as IXmlDocumentIO " << std::hex
                   << hr;
-      return hr;
+      return nullptr;
     }
 
     base::string16 notification_template =
@@ -192,7 +189,7 @@
       LogDisplayHistogram(DisplayStatus::LOAD_XML_FAILED);
       DLOG(ERROR) << "Unable to load the template's XML into the document "
                   << std::hex << hr;
-      return hr;
+      return nullptr;
     }
 
     mswr::ComPtr<winxml::Dom::IXmlDocument> document;
@@ -200,7 +197,7 @@
     if (FAILED(hr)) {
       LogDisplayHistogram(DisplayStatus::CONVERSION_FAILED_XML_IO_TO_XML);
       DLOG(ERROR) << "Unable to get as XMLDocument " << std::hex << hr;
-      return hr;
+      return nullptr;
     }
 
     mswr::ComPtr<winui::Notifications::IToastNotificationFactory>
@@ -212,25 +209,26 @@
       LogDisplayHistogram(DisplayStatus::CREATE_FACTORY_FAILED);
       DLOG(ERROR) << "Unable to create the IToastNotificationFactory "
                   << std::hex << hr;
-      return hr;
+      return nullptr;
     }
 
+    mswr::ComPtr<winui::Notifications::IToastNotification> toast_notification;
     hr = toast_notification_factory->CreateToastNotification(
-        document.Get(), toast_notification);
+        document.Get(), toast_notification.GetAddressOf());
     if (FAILED(hr)) {
       LogDisplayHistogram(DisplayStatus::CREATE_TOAST_NOTIFICATION_FAILED);
       DLOG(ERROR) << "Unable to create the IToastNotification " << std::hex
                   << hr;
-      return hr;
+      return nullptr;
     }
 
     mswr::ComPtr<winui::Notifications::IToastNotification2> toast2;
-    hr = (*toast_notification)->QueryInterface(IID_PPV_ARGS(&toast2));
+    hr = toast_notification->QueryInterface(IID_PPV_ARGS(&toast2));
     if (FAILED(hr)) {
       LogDisplayHistogram(DisplayStatus::CREATE_TOAST_NOTIFICATION2_FAILED);
       DLOG(ERROR) << "Failed to get IToastNotification2 object " << std::hex
                   << hr;
-      return hr;
+      return nullptr;
     }
 
     // Set the Group and Tag values for the notification, in order to support
@@ -249,14 +247,14 @@
     if (FAILED(hr)) {
       LogDisplayHistogram(DisplayStatus::SETTING_GROUP_FAILED);
       DLOG(ERROR) << "Failed to set Group " << std::hex << hr;
-      return hr;
+      return nullptr;
     }
 
     hr = toast2->put_Tag(tag.get());
     if (FAILED(hr)) {
       LogDisplayHistogram(DisplayStatus::SETTING_TAG_FAILED);
       DLOG(ERROR) << "Failed to set Tag " << std::hex << hr;
-      return hr;
+      return nullptr;
     }
 
     // By default, Windows 10 will always show the notification on screen.
@@ -278,7 +276,7 @@
         if (FAILED(hr)) {
           LogDisplayHistogram(DisplayStatus::GET_GROUP_FAILED);
           DLOG(ERROR) << "Failed to get group value " << std::hex << hr;
-          return hr;
+          return nullptr;
         }
         ScopedHString scoped_group(hstring_group);
 
@@ -287,7 +285,7 @@
         if (FAILED(hr)) {
           LogDisplayHistogram(DisplayStatus::GET_TAG_FAILED);
           DLOG(ERROR) << "Failed to get tag value " << std::hex << hr;
-          return hr;
+          return nullptr;
         }
         ScopedHString scoped_tag(hstring_tag);
 
@@ -298,12 +296,12 @@
         if (FAILED(hr)) {
           LogDisplayHistogram(DisplayStatus::SUPPRESS_POPUP_FAILED);
           DLOG(ERROR) << "Failed to set suppress value " << std::hex << hr;
-          return hr;
+          return nullptr;
         }
       }
     }
 
-    return S_OK;
+    return toast_notification;
   }
 
   void Display(NotificationHandler::Type notification_type,
@@ -360,14 +358,11 @@
     std::unique_ptr<NotificationTemplateBuilder> notification_template =
         NotificationTemplateBuilder::Build(
             image_retainer_->AsWeakPtr(), launch_id, profile_id, *notification);
-    mswr::ComPtr<winui::Notifications::IToastNotification> toast;
-    hr = GetToastNotification(*notification, *notification_template, profile_id,
-                              incognito, &toast);
-    if (FAILED(hr)) {
-      // A histogram should have already been logged for this failure.
-      DLOG(ERROR) << "Unable to get a toast notification " << std::hex << hr;
+    mswr::ComPtr<winui::Notifications::IToastNotification> toast =
+        GetToastNotification(*notification, *notification_template, profile_id,
+                             incognito);
+    if (!toast)
       return;
-    }
 
     // Activation via user interaction with the toast is handled in
     // HandleActivation() by way of the notification_helper.
@@ -408,8 +403,9 @@
              const std::string& notification_id) {
     DCHECK(notification_task_runner_->RunsTasksInCurrentSequence());
 
-    mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history;
-    if (!GetIToastNotificationHistory(&history)) {
+    mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history =
+        GetIToastNotificationHistory();
+    if (!history) {
       LogCloseHistogram(CloseStatus::GET_TOAST_HISTORY_FAILED);
       DLOG(ERROR) << "Failed to get IToastNotificationHistory";
       return;
@@ -431,9 +427,8 @@
     }
   }
 
-  bool GetIToastNotificationHistory(
-      winui::Notifications::IToastNotificationHistory** notification_history)
-      const WARN_UNUSED_RESULT {
+  mswr::ComPtr<winui::Notifications::IToastNotificationHistory>
+  GetIToastNotificationHistory() const WARN_UNUSED_RESULT {
     mswr::ComPtr<winui::Notifications::IToastNotificationManagerStatics>
         toast_manager;
     HRESULT hr = CreateActivationFactory(
@@ -444,7 +439,7 @@
           HistoryStatus::CREATE_TOAST_NOTIFICATION_MANAGER_FAILED);
       DLOG(ERROR) << "Unable to create the ToastNotificationManager "
                   << std::hex << hr;
-      return false;
+      return nullptr;
     }
 
     mswr::ComPtr<winui::Notifications::IToastNotificationManagerStatics2>
@@ -457,26 +452,30 @@
           HistoryStatus::QUERY_TOAST_MANAGER_STATISTICS2_FAILED);
       DLOG(ERROR) << "Failed to get IToastNotificationManagerStatics2 "
                   << std::hex << hr;
-      return false;
+      return nullptr;
     }
 
-    hr = toast_manager2->get_History(notification_history);
+    mswr::ComPtr<winui::Notifications::IToastNotificationHistory>
+        notification_history;
+    hr = toast_manager2->get_History(notification_history.GetAddressOf());
     if (FAILED(hr)) {
       LogHistoryHistogram(HistoryStatus::GET_TOAST_HISTORY_FAILED);
       DLOG(ERROR) << "Failed to get IToastNotificationHistory " << std::hex
                   << hr;
-      return false;
+      return nullptr;
     }
 
     LogHistoryHistogram(HistoryStatus::SUCCESS);
-    return true;
+
+    return notification_history;
   }
 
   std::vector<mswr::ComPtr<winui::Notifications::IToastNotification>>
   GetDisplayedFromActionCenter(const std::string& profile_id,
                                bool incognito) const {
-    mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history;
-    if (!GetIToastNotificationHistory(&history)) {
+    mswr::ComPtr<winui::Notifications::IToastNotificationHistory> history =
+        GetIToastNotificationHistory();
+    if (!history) {
       LogGetDisplayedStatus(GetDisplayedStatus::GET_TOAST_HISTORY_FAILED);
       DLOG(ERROR) << "Failed to get IToastNotificationHistory";
       return {};
@@ -920,13 +919,12 @@
   NotificationPlatformBridgeWinImpl::notifier_for_testing_ = notifier;
 }
 
-HRESULT NotificationPlatformBridgeWin::GetToastNotificationForTesting(
+mswr::ComPtr<winui::Notifications::IToastNotification>
+NotificationPlatformBridgeWin::GetToastNotificationForTesting(
     const message_center::Notification& notification,
     const NotificationTemplateBuilder& notification_template_builder,
     const std::string& profile_id,
-    bool incognito,
-    winui::Notifications::IToastNotification** toast_notification) {
-  return impl_->GetToastNotification(notification,
-                                     notification_template_builder, profile_id,
-                                     incognito, toast_notification);
+    bool incognito) {
+  return impl_->GetToastNotification(
+      notification, notification_template_builder, profile_id, incognito);
 }
diff --git a/chrome/browser/notifications/notification_platform_bridge_win.h b/chrome/browser/notifications/notification_platform_bridge_win.h
index 7e4f489..315718e 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win.h
+++ b/chrome/browser/notifications/notification_platform_bridge_win.h
@@ -82,12 +82,12 @@
 
   // Obtain an IToastNotification interface from a given XML (provided by the
   // NotificationTemplateBuilder). For testing use only.
-  HRESULT GetToastNotificationForTesting(
+  Microsoft::WRL::ComPtr<ABI::Windows::UI::Notifications::IToastNotification>
+  GetToastNotificationForTesting(
       const message_center::Notification& notification,
       const NotificationTemplateBuilder& notification_template_builder,
       const std::string& profile_id,
-      bool incognito,
-      ABI::Windows::UI::Notifications::IToastNotification** toast_notification);
+      bool incognito);
 
   scoped_refptr<NotificationPlatformBridgeWinImpl> impl_;
 
diff --git a/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc b/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
index ddb5175a..597ee09 100644
--- a/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_win_unittest.cc
@@ -54,12 +54,11 @@
             std::make_unique<NotificationPlatformBridgeWin>()) {}
   ~NotificationPlatformBridgeWinTest() override = default;
 
-  HRESULT GetToast(
+  mswr::ComPtr<winui::Notifications::IToastNotification2> GetToast(
       const NotificationLaunchId& launch_id,
       bool renotify,
       const std::string& profile_id,
-      bool incognito,
-      mswr::ComPtr<winui::Notifications::IToastNotification2>* toast2) {
+      bool incognito) {
     GURL origin(kOrigin);
     auto notification = std::make_unique<message_center::Notification>(
         message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, L"title",
@@ -72,22 +71,22 @@
         NotificationTemplateBuilder::Build(
             image_retainer->AsWeakPtr(), launch_id, profile_id, *notification);
 
-    mswr::ComPtr<winui::Notifications::IToastNotification> toast;
-    HRESULT hr =
+    mswr::ComPtr<winui::Notifications::IToastNotification> toast =
         notification_platform_bridge_win_->GetToastNotificationForTesting(
-            *notification, *builder, profile_id, incognito, &toast);
-    if (FAILED(hr)) {
+            *notification, *builder, profile_id, incognito);
+    if (!toast) {
       LOG(ERROR) << "GetToastNotificationForTesting failed";
-      return hr;
+      return nullptr;
     }
 
-    hr = toast.As<winui::Notifications::IToastNotification2>(toast2);
+    mswr::ComPtr<winui::Notifications::IToastNotification2> toast2;
+    HRESULT hr = toast.As<winui::Notifications::IToastNotification2>(&toast2);
     if (FAILED(hr)) {
       LOG(ERROR) << "Converting to IToastNotification2 failed";
-      return hr;
+      return nullptr;
     }
 
-    return S_OK;
+    return toast2;
   }
 
  protected:
@@ -111,9 +110,10 @@
   NotificationLaunchId launch_id(kLaunchId);
   ASSERT_TRUE(launch_id.is_valid());
 
-  mswr::ComPtr<winui::Notifications::IToastNotification2> toast2;
-  ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, kProfileId,
-                                    /*incognito=*/false, &toast2));
+  mswr::ComPtr<winui::Notifications::IToastNotification2> toast2 =
+      GetToast(launch_id, /*renotify=*/false, kProfileId,
+               /*incognito=*/false);
+  ASSERT_TRUE(toast2);
 
   HSTRING hstring_group;
   ASSERT_HRESULT_SUCCEEDED(toast2->get_Group(&hstring_group));
@@ -149,10 +149,13 @@
 
   // Different profiles, same incognito status -> Unique tags.
   {
-    ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1",
-                                      /*incognito=*/true, &toastA));
-    ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile2",
-                                      /*incognito=*/true, &toastB));
+    toastA = GetToast(launch_id, /*renotify=*/false, "Profile1",
+                      /*incognito=*/true);
+    toastB = GetToast(launch_id, /*renotify=*/false, "Profile2",
+                      /*incognito=*/true);
+
+    ASSERT_TRUE(toastA);
+    ASSERT_TRUE(toastB);
 
     ASSERT_HRESULT_SUCCEEDED(toastA->get_Tag(&hstring_tagA));
     base::win::ScopedHString tagA(hstring_tagA);
@@ -165,10 +168,13 @@
 
   // Same profile, different incognito status -> Unique tags.
   {
-    ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1",
-                                      /*incognito=*/true, &toastA));
-    ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1",
-                                      /*incognito=*/false, &toastB));
+    toastA = GetToast(launch_id, /*renotify=*/false, "Profile1",
+                      /*incognito=*/true);
+    toastB = GetToast(launch_id, /*renotify=*/false, "Profile1",
+                      /*incognito=*/false);
+
+    ASSERT_TRUE(toastA);
+    ASSERT_TRUE(toastB);
 
     ASSERT_HRESULT_SUCCEEDED(toastA->get_Tag(&hstring_tagA));
     base::win::ScopedHString tagA(hstring_tagA);
@@ -181,10 +187,13 @@
 
   // Same profile, same incognito status -> Identical tags.
   {
-    ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1",
-                                      /*incognito=*/true, &toastA));
-    ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, "Profile1",
-                                      /*incognito=*/true, &toastB));
+    toastA = GetToast(launch_id, /*renotify=*/false, "Profile1",
+                      /*incognito=*/true);
+    toastB = GetToast(launch_id, /*renotify=*/false, "Profile1",
+                      /*incognito=*/true);
+
+    ASSERT_TRUE(toastA);
+    ASSERT_TRUE(toastB);
 
     ASSERT_HRESULT_SUCCEEDED(toastA->get_Tag(&hstring_tagA));
     base::win::ScopedHString tagA(hstring_tagA);
@@ -218,10 +227,12 @@
 
   // Make sure this works a toast is not suppressed when no notifications are
   // registered.
-  ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, kProfileId,
-                                    /*incognito=*/false, &toast2));
+  toast2 = GetToast(launch_id, /*renotify=*/false, kProfileId,
+                    /*incognito=*/false);
+  ASSERT_TRUE(toast2);
   ASSERT_HRESULT_SUCCEEDED(toast2->get_SuppressPopup(&suppress));
   ASSERT_FALSE(suppress);
+  toast2.Reset();
 
   // Register a single notification with a specific tag.
   std::string tag_data = std::string(kNotificationId) + "|" + kProfileId + "|0";
@@ -232,16 +243,20 @@
       L"<toast launch=\"0|0|Default|0|https://foo.com/|id\"></toast>", tag));
 
   // Request this notification with renotify true (should not be suppressed).
-  ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/true, kProfileId,
-                                    /*incognito=*/false, &toast2));
+  toast2 = GetToast(launch_id, /*renotify=*/true, kProfileId,
+                    /*incognito=*/false);
+  ASSERT_TRUE(toast2);
   ASSERT_HRESULT_SUCCEEDED(toast2->get_SuppressPopup(&suppress));
   ASSERT_FALSE(suppress);
+  toast2.Reset();
 
   // Request this notification with renotify false (should be suppressed).
-  ASSERT_HRESULT_SUCCEEDED(GetToast(launch_id, /*renotify=*/false, kProfileId,
-                                    /*incognito=*/false, &toast2));
+  toast2 = GetToast(launch_id, /*renotify=*/false, kProfileId,
+                    /*incognito=*/false);
+  ASSERT_TRUE(toast2);
   ASSERT_HRESULT_SUCCEEDED(toast2->get_SuppressPopup(&suppress));
   ASSERT_TRUE(suppress);
+  toast2.Reset();
 
   notification_platform_bridge_win_->SetDisplayedNotificationsForTesting(
       nullptr);
diff --git a/chrome/browser/notifications/win/OWNERS b/chrome/browser/notifications/win/OWNERS
index 118c023..1c89641 100644
--- a/chrome/browser/notifications/win/OWNERS
+++ b/chrome/browser/notifications/win/OWNERS
@@ -1,3 +1,4 @@
+chengx@chromium.org
 finnur@chromium.org
 
 per-file notification_helper*=file://chrome/notification_helper/OWNERS
diff --git a/chrome/browser/notifications/win/notification_image_retainer.cc b/chrome/browser/notifications/win/notification_image_retainer.cc
index d627e639..a8f3abb 100644
--- a/chrome/browser/notifications/win/notification_image_retainer.cc
+++ b/chrome/browser/notifications/win/notification_image_retainer.cc
@@ -6,12 +6,11 @@
 
 #include "base/files/file_util.h"
 #include "base/hash.h"
+#include "base/memory/ref_counted_memory.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "base/threading/thread_restrictions.h"
-#include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "chrome/common/chrome_paths.h"
 #include "ui/gfx/image/image.h"
@@ -28,25 +27,34 @@
 // notifications that can be shown on-screen at once (1).
 constexpr base::TimeDelta kDeletionDelay = base::TimeDelta::FromSeconds(12);
 
-// Writes |data| to a new temporary file and returns the path to the new file,
-// or an empty path if the function fails.
-base::FilePath WriteDataToTmpFile(
-    const base::FilePath& file_path,
-    const base::string16& subdirectory,
-    const scoped_refptr<base::RefCountedMemory>& data) {
-  int data_len = data->size();
-  if (data_len == 0)
-    return base::FilePath();
+// Returns the temporary directory within the user data directory. The regular
+// temporary directory is not used to minimize the risk of files getting deleted
+// by accident. It is also not profile-bound because the notification bridge
+// handles images for multiple profiles and the separation is handled by
+// RegisterTemporaryImage.
+base::FilePath DetermineImageDirectory() {
+  base::FilePath data_dir;
+  bool success = base::PathService::Get(chrome::DIR_USER_DATA, &data_dir);
+  DCHECK(success);
+  return data_dir.Append(kImageRoot);
+}
 
-  base::FilePath new_temp = file_path.Append(subdirectory);
-  if (!base::CreateDirectoryAndGetError(new_temp, nullptr))
+// Writes |data| to a new temporary file at |dir_path| and returns the path to
+// the new file, or an empty path if the function fails.
+base::FilePath WriteDataToTmpFile(
+    const base::FilePath& dir_path,
+    const scoped_refptr<base::RefCountedMemory>& data) {
+  if (!base::CreateDirectoryAndGetError(dir_path, nullptr))
     return base::FilePath();
 
   base::FilePath temp_file;
-  if (!base::CreateTemporaryFileInDir(new_temp, &temp_file))
+  if (!base::CreateTemporaryFileInDir(dir_path, &temp_file))
     return base::FilePath();
+
+  int data_len = data->size();
   if (base::WriteFile(temp_file, data->front_as<char>(), data_len) != data_len)
     return base::FilePath();
+
   return temp_file;
 }
 
@@ -68,6 +76,11 @@
     const std::string& profile_id,
     const GURL& origin) {
   base::AssertBlockingAllowed();
+
+  scoped_refptr<base::RefCountedMemory> image_data = image.As1xPNGBytes();
+  if (image_data->size() == 0)
+    return base::FilePath();
+
   if (!initialized_) {
     image_directory_ = DetermineImageDirectory();
     // Delete the old image directory.
@@ -84,7 +97,7 @@
   base::string16 directory =
       base::UintToString16(base::Hash(profile_id + origin.spec()));
   base::FilePath temp_file =
-      WriteDataToTmpFile(image_directory_, directory, image.As1xPNGBytes());
+      WriteDataToTmpFile(image_directory_.Append(directory), image_data);
 
   // Add a future task to try to delete the file. It is OK to fail, the file
   // will get deleted later.
@@ -105,10 +118,3 @@
     bool override_file_destruction) {
   override_file_destruction_ = override_file_destruction;
 }
-
-base::FilePath NotificationImageRetainer::DetermineImageDirectory() {
-  base::FilePath data_dir;
-  bool success = base::PathService::Get(chrome::DIR_USER_DATA, &data_dir);
-  DCHECK(success);
-  return data_dir.Append(kImageRoot);
-}
diff --git a/chrome/browser/notifications/win/notification_image_retainer.h b/chrome/browser/notifications/win/notification_image_retainer.h
index 96c3603f..4516a3f 100644
--- a/chrome/browser/notifications/win/notification_image_retainer.h
+++ b/chrome/browser/notifications/win/notification_image_retainer.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/sequenced_task_runner.h"
 
@@ -51,13 +52,6 @@
       bool override_file_destruction);
 
  private:
-  // Returns the temporary directory within the user data directory. The
-  // regular temporary directory is not used to minimize the risk of files
-  // getting deleted by accident. It is also not profile-bound because the
-  // notification bridge handles images for multiple profiles and the separation
-  // is handled by RegisterTemporaryImage.
-  base::FilePath DetermineImageDirectory();
-
   // The path to where to store the temporary files.
   base::FilePath image_directory_;
 
diff --git a/chrome/browser/password_manager/password_store_factory.cc b/chrome/browser/password_manager/password_store_factory.cc
index 0452fd49..e30d22b 100644
--- a/chrome/browser/password_manager/password_store_factory.cc
+++ b/chrome/browser/password_manager/password_store_factory.cc
@@ -289,8 +289,7 @@
   ps->PreparePasswordHashData(GetSyncUsername(profile));
 #endif
 
-  password_manager_util::DeleteBlacklistedDuplicates(ps.get(),
-                                                     profile->GetPrefs(), 60);
+  password_manager_util::RemoveUselessCredentials(ps, profile->GetPrefs(), 60);
   auto network_context_getter = base::BindRepeating(
       [](Profile* profile) -> network::mojom::NetworkContext* {
         if (!g_browser_process->profile_manager()->IsValidProfile(profile))
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc
index 4d313b0..b825908e 100644
--- a/chrome/browser/pdf/pdf_extension_test.cc
+++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -40,7 +40,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/ui_test_utils.h"
-#include "chrome/test/views/scoped_macviews_browser_mode.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/download/public/common/download_item.h"
 #include "components/viz/common/features.h"
@@ -380,10 +379,6 @@
   }
 
   base::test::ScopedFeatureList feature_list_;
-
-#if defined(OS_MACOSX)
-  test::ScopedMacViewsBrowserMode cocoa_browser_mode_{false};
-#endif
 };
 
 // Disabled because it's flaky.
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index 83cb9551..297fb69d 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -1174,15 +1174,10 @@
 
 #if !defined(OS_ANDROID)
 
-// TODO(mlamouri): enable this tests on other platforms when aspect ratio is
-// implemented.
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
-
 // Tests that when a new surface id is sent to the Picture-in-Picture window, it
 // doesn't move back to its default position.
-// TODO(https://crbug.com/862505): test is currently flaky.
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
-                       DISABLED_SurfaceIdChangeDoesNotMoveWindow) {
+                       SurfaceIdChangeDoesNotMoveWindow) {
   LoadTabAndEnterPictureInPicture(browser());
 
   content::WebContents* active_web_contents =
@@ -1208,7 +1203,8 @@
             content::TitleWatcher(active_web_contents, expected_title)
                 .WaitAndGetTitle());
 
-  // Simulate a new surface layer and a change in aspect ratio and wait for ack.
+  // Simulate a new surface layer and a change in aspect ratio then wait for
+  // ack.
   {
     WidgetBoundsChangeWaiter waiter(overlay_window);
 
@@ -1228,8 +1224,6 @@
   EXPECT_LT(overlay_window->GetBounds().y(), 100);
 }
 
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
-
 // Tests that the Picture-in-Picture state is properly updated when the window
 // is closed at a system level.
 IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
@@ -1444,8 +1438,8 @@
                 .WaitAndGetTitle());
 
   // Attaching devtools triggers the change in timing that leads to the crash.
-  DevToolsWindowTesting::OpenDevToolsWindowSync(browser(),
-                                                true /*is_docked=*/);
+  DevToolsWindow* window = DevToolsWindowTesting::OpenDevToolsWindowSync(
+      browser(), true /*is_docked=*/);
 
   {
     bool result = false;
@@ -1468,6 +1462,10 @@
   content::WebContentsDestroyedWatcher destroyed_watcher(active_web_contents);
   browser()->tab_strip_model()->CloseWebContentsAt(0, 0);
   destroyed_watcher.Wait();
+
+  // Make sure the window and therefore Chrome_DevToolsADBThread shutdown
+  // gracefully.
+  DevToolsWindowTesting::CloseDevToolsWindowSync(window);
 }
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 7d4305b..2aa2cbd 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -117,6 +117,7 @@
 #include "components/subresource_filter/content/browser/ruleset_service.h"
 #include "components/sync/base/sync_prefs.h"
 #include "components/sync_preferences/pref_service_syncable.h"
+#include "components/sync_sessions/session_sync_prefs.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/update_client/update_client.h"
 #include "components/variations/service/variations_service.h"
@@ -590,6 +591,7 @@
   secure_origin_whitelist::RegisterProfilePrefs(registry);
   SafeBrowsingTriggeredPopupBlocker::RegisterProfilePrefs(registry);
   SessionStartupPref::RegisterProfilePrefs(registry);
+  sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry);
   syncer::SyncPrefs::RegisterProfilePrefs(registry);
   syncer::PerUserTopicRegistrationManager::RegisterProfilePrefs(registry);
   TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/resource_coordinator/discard_before_unload_helper.cc b/chrome/browser/resource_coordinator/discard_before_unload_helper.cc
new file mode 100644
index 0000000..23510df
--- /dev/null
+++ b/chrome/browser/resource_coordinator/discard_before_unload_helper.cc
@@ -0,0 +1,120 @@
+// 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/resource_coordinator/discard_before_unload_helper.h"
+
+#include "base/bind.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace resource_coordinator {
+
+namespace {
+
+// This is a helper class that determines whether or not there is a beforeunload
+// handler associated with a given WebContents, and if so, whether or not it
+// indicates that the page contains unsaved state.
+//
+// This is done by actually running the beforeunload handler if there is one. If
+// the beforeunload handler returns a non-empty string then a javascript dialog
+// request is made, in which case it is intercepted before it is displayed and
+// implicitly canceled.
+//
+// The beforeunload is initiated via WebContents::DispatchBeforeUnload, and the
+// outcome of the beforeunload is monitored via
+// WebContentsObserver::BeforeUnloadFired and ::BeforeUnloadDialogCanceled.
+//
+// Note that the callback is guaranteed to be invoked; in the worst case
+// scenario it will be invoked when the WebContents is destroyed, with a
+// |proceed|=true value.
+class DiscardBeforeUnloadHelper : public content::WebContentsObserver {
+ public:
+  static void HasBeforeUnloadHandler(content::WebContents* contents,
+                                     HasBeforeUnloadHandlerCallback&& callback);
+
+  ~DiscardBeforeUnloadHelper() override;
+
+ private:
+  // This is only meant to be called via "new", as the object takes ownership
+  // of itself.
+  DiscardBeforeUnloadHelper(content::WebContents* contents,
+                            HasBeforeUnloadHandlerCallback&& callback);
+
+  // WebContentsObserver:
+  void BeforeUnloadFired(bool proceed,
+                         const base::TimeTicks& proceed_time) override;
+  void BeforeUnloadDialogCancelled() override;
+  void WebContentsDestroyed() override;
+
+  // Responds by invoking the callback, and cleaning itself up.
+  void Respond(bool has_beforeunload_handler);
+
+  // This object keeps itself alive while waiting for a callback, and cleans
+  // itself up when done.
+  std::unique_ptr<DiscardBeforeUnloadHelper> self_;
+
+  HasBeforeUnloadHandlerCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiscardBeforeUnloadHelper);
+};
+
+void DiscardBeforeUnloadHelper::HasBeforeUnloadHandler(
+    content::WebContents* contents,
+    HasBeforeUnloadHandlerCallback&& callback) {
+  // Create this object and deliberately let go of it. It deletes itself after
+  // it has invoked the callback.
+  new DiscardBeforeUnloadHelper(contents, std::move(callback));
+}
+
+DiscardBeforeUnloadHelper::DiscardBeforeUnloadHelper(
+    content::WebContents* contents,
+    HasBeforeUnloadHandlerCallback&& callback)
+    : WebContentsObserver(contents),
+      self_(this),
+      callback_(std::move(callback)) {
+  DCHECK(!callback_.is_null());
+  // NOTE: Ideally this would call NeedToFireBeforeUnload and entirely skip
+  // on the dispatch if there are no unload handlers installed. Unfortunately,
+  // NeedToFireBeforeUnload doesn't check the main frame, so this doesn't quite
+  // work. See this related bug for more information: crbug.com/869956
+  web_contents()->DispatchBeforeUnload(true /* auto_cancel */);
+}
+
+DiscardBeforeUnloadHelper::~DiscardBeforeUnloadHelper() = default;
+
+void DiscardBeforeUnloadHelper::BeforeUnloadFired(
+    bool proceed,
+    const base::TimeTicks& proceed_time) {
+  // |proceed = true| means no beforeunload handler and vice-versa.
+  Respond(!proceed /* has_beforeunload_handler */);
+}
+
+void DiscardBeforeUnloadHelper::BeforeUnloadDialogCancelled() {
+  // Canceling a beforeunload dialog means that there was a beforeunload handler
+  // that was already running prior to our request, and more specifically that
+  // the user wants to stay on the page.
+  Respond(true /* has_beforeunload_handler */);
+}
+
+void DiscardBeforeUnloadHelper::WebContentsDestroyed() {
+  // If a WebContents is destroyed while waiting for the beforeunload response
+  // this can be interpreted as |proceed| being true, as the page is no longer
+  // going to be around to be preserved.
+  Respond(false /* has_beforeunload_handler */);
+}
+
+void DiscardBeforeUnloadHelper::Respond(bool has_beforeunload_handler) {
+  std::move(callback_).Run(has_beforeunload_handler);
+  self_.reset();
+}
+
+}  // namespace
+
+void HasBeforeUnloadHandler(content::WebContents* contents,
+                            HasBeforeUnloadHandlerCallback&& callback) {
+  DiscardBeforeUnloadHelper::HasBeforeUnloadHandler(contents,
+                                                    std::move(callback));
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resource_coordinator/discard_before_unload_helper.h b/chrome/browser/resource_coordinator/discard_before_unload_helper.h
new file mode 100644
index 0000000..d2ae716
--- /dev/null
+++ b/chrome/browser/resource_coordinator/discard_before_unload_helper.h
@@ -0,0 +1,30 @@
+// 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_RESOURCE_COORDINATOR_DISCARD_BEFORE_UNLOAD_HELPER_H_
+#define CHROME_BROWSER_RESOURCE_COORDINATOR_DISCARD_BEFORE_UNLOAD_HELPER_H_
+
+#include "base/callback.h"
+
+namespace content {
+class WebContents;
+}  // namespace content
+
+namespace resource_coordinator {
+
+using HasBeforeUnloadHandlerCallback =
+    base::OnceCallback<void(bool has_before_unload_handler)>;
+
+// Determines if the given WebContents has a beforeunload handler; if not, it is
+// safe to discard. This works by calling WebContents::DispatchBeforeUnload with
+// |auto_cancel = true|, which prevents a beforeunload dialog from being
+// displayed to the user in the case that there is a beforeunload handler. This
+// should only be called from the UI thread, and the callback will similarly
+// be invoked from there.
+void HasBeforeUnloadHandler(content::WebContents* contents,
+                            HasBeforeUnloadHandlerCallback&& callback);
+
+}  // namespace resource_coordinator
+
+#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_DISCARD_BEFORE_UNLOAD_HELPER_H_
diff --git a/chrome/browser/resource_coordinator/discard_before_unload_helper_browsertest.cc b/chrome/browser/resource_coordinator/discard_before_unload_helper_browsertest.cc
new file mode 100644
index 0000000..a0f2e0e
--- /dev/null
+++ b/chrome/browser/resource_coordinator/discard_before_unload_helper_browsertest.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 "chrome/browser/resource_coordinator/discard_before_unload_helper.h"
+
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/app_modal/javascript_app_modal_dialog.h"
+#include "components/app_modal/native_app_modal_dialog.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "url/gurl.h"
+
+namespace resource_coordinator {
+
+namespace {
+
+class HasBeforeUnloadHandlerTest : public InProcessBrowserTest {
+ protected:
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    host_resolver()->AddRule("*", "127.0.0.1");
+    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
+    embedded_test_server()->ServeFilesFromSourceDirectory("chrome/test/data");
+    embedded_test_server()->StartAcceptingConnections();
+  }
+
+  void TestDiscardBeforeUnloadHelper(const char* url,
+                                     bool has_beforeunload_helper) {
+    GURL gurl(embedded_test_server()->GetURL("a.com", url));
+    ui_test_utils::NavigateToURL(browser(), gurl);
+    auto* wc = browser()->tab_strip_model()->GetActiveWebContents();
+    content::PrepContentsForBeforeUnloadTest(wc);
+
+    base::RunLoop run_loop;
+    bool callback_invoked = false;
+    bool response = false;
+    HasBeforeUnloadHandlerCallback callback = base::BindLambdaForTesting(
+        [&run_loop, &callback_invoked, &response](bool response_arg) {
+          run_loop.Quit();
+          callback_invoked = true;
+          response = response_arg;
+        });
+
+    HasBeforeUnloadHandler(wc, std::move(callback));
+
+    // The callback should not be invoked synchronously. In a world where
+    // NeedToFireBeforeUnload works properly this expectation changes.
+    ASSERT_FALSE(callback_invoked);
+
+    // Run the loop until we process the callback.
+    run_loop.Run();
+
+    EXPECT_TRUE(callback_invoked);
+    EXPECT_EQ(has_beforeunload_helper, response);
+
+    // If we didn't expect to proceed, then that means there's an unload
+    // handler. Which means that when we try to exit the browser a dialog will
+    // be shown. Wait for it, and accept it to allow the browser to close and
+    // the test to complete.
+    browser()->tab_strip_model()->CloseAllTabs();
+    if (has_beforeunload_helper) {
+      app_modal::JavaScriptAppModalDialog* alert =
+          ui_test_utils::WaitForAppModalDialog();
+      ASSERT_TRUE(alert);
+      EXPECT_TRUE(alert->is_before_unload_dialog());
+      alert->native_dialog()->AcceptAppModalDialog();
+    }
+  }
+};
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest,
+                       NonEmptyBeforeUnloadDetected) {
+  TestDiscardBeforeUnloadHelper("/beforeunload.html",
+                                true /* has_beforeunload_helper */);
+}
+
+IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest, EmptyBeforeUnloadDetected) {
+  TestDiscardBeforeUnloadHelper("/emptybeforeunload.html",
+                                false /* has_beforeunload_helper */);
+}
+
+IN_PROC_BROWSER_TEST_F(HasBeforeUnloadHandlerTest, NoBeforeUnloadDetected) {
+  TestDiscardBeforeUnloadHelper("/empty.html",
+                                false /* has_beforeunload_helper */);
+}
+
+}  // namespace resource_coordinator
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
index 8fc78677..f5b6985 100644
--- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
+++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -432,11 +432,6 @@
           AutomationPredicate.linkOrControl(node);
     };
 
-    // Always try to give nodes selection.
-    if (start.defaultActionVerb == chrome.automation.DefaultActionVerb.SELECT) {
-      start.doDefault();
-    }
-
     // Next, try to focus the start or end node.
     if (!AutomationPredicate.structuralContainer(start) &&
         start.state[StateType.FOCUSABLE]) {
diff --git a/chrome/browser/resources/local_ntp/custom_backgrounds.js b/chrome/browser/resources/local_ntp/custom_backgrounds.js
index a042caa1..5c97d5c 100644
--- a/chrome/browser/resources/local_ntp/custom_backgrounds.js
+++ b/chrome/browser/resources/local_ntp/custom_backgrounds.js
@@ -902,6 +902,9 @@
       .setAttribute(
           'aria-label', configData.translatedStrings.customizeThisPage);
 
+  $(customBackgrounds.IDS.EDIT_BG_GEAR)
+      .setAttribute('title', configData.translatedStrings.customizeBackground);
+
   // Edit gear icon interaction events.
   let editBackgroundInteraction = function() {
     editDialog.showModal();
diff --git a/chrome/browser/resources/omnibox/omnibox.html b/chrome/browser/resources/omnibox/omnibox.html
index ccaaa686..7360c58 100644
--- a/chrome/browser/resources/omnibox/omnibox.html
+++ b/chrome/browser/resources/omnibox/omnibox.html
@@ -17,7 +17,6 @@
       <p>
         Enter omnibox input text:
         <input id="input-text" type="text" size="40" autofocus>
-        <input type="submit">
       </p>
       <p>Input parameters:</p>
       <p>
diff --git a/chrome/browser/resources/omnibox/omnibox.js b/chrome/browser/resources/omnibox/omnibox.js
index 33cfac1..078ae73 100644
--- a/chrome/browser/resources/omnibox/omnibox.js
+++ b/chrome/browser/resources/omnibox/omnibox.js
@@ -22,7 +22,7 @@
    * Register our event handlers.
    */
   function initialize() {
-    $('omnibox-input-form').addEventListener('submit', startOmniboxQuery, false);
+    $('input-text').addEventListener('input', startOmniboxQuery, false);
     $('prevent-inline-autocomplete')
         .addEventListener('change', startOmniboxQuery);
     $('prefer-keyword').addEventListener('change', startOmniboxQuery);
diff --git a/chrome/browser/resources/print_preview/new/destination_dialog.html b/chrome/browser/resources/print_preview/new/destination_dialog.html
index fe21ce5..efedf4d1b 100644
--- a/chrome/browser/resources/print_preview/new/destination_dialog.html
+++ b/chrome/browser/resources/print_preview/new/destination_dialog.html
@@ -54,7 +54,7 @@
       }
 
       .user-info {
-        font-size: calc(13/15 * 1em);
+        font-size: calc(13 / 15 * 1em);
         line-height: normal;
         margin-bottom: 14px;
         margin-top: 8px;
@@ -77,7 +77,7 @@
       /* Height = 3 * destination item (28px) + 10px padding + 1 line text */
       #recentList {
         flex: 0;
-        min-height: calc(94px + 1rem);
+        min-height: calc(94px + 20 / 13 * 1rem);
         padding-bottom: 18px;
       }
 
@@ -85,12 +85,12 @@
       /* header (82px + 1 line) - button (64px) - 2px spinner - 2px extra */
       #printList {
         flex: 1;
-        min-height: calc(94px + 1rem);
+        min-height: calc(94px + 20 / 13 * 1rem);
         padding-bottom: 0;
       }
 
       paper-button {
-        font-size: calc(12/13 * 1em);
+        font-size: calc(12 / 13 * 1em);
       }
 
       #dialog #promos {
@@ -140,7 +140,7 @@
 
       #invitationPromo invitation-details {
         color: var(--google-grey-refresh-700);
-        font-size: calc(10/13 * 1em);
+        font-size: calc(10 / 13 * 1em);
         font-weight: 500;
       }
     </style>
diff --git a/chrome/browser/resources/print_preview/new/destination_list.html b/chrome/browser/resources/print_preview/new/destination_list.html
index 28a0125..0a74336 100644
--- a/chrome/browser/resources/print_preview/new/destination_list.html
+++ b/chrome/browser/resources/print_preview/new/destination_list.html
@@ -26,6 +26,7 @@
 
       #listContainer {
         flex: 1;
+        min-height: 0;
       }
 
       .title,
@@ -39,7 +40,8 @@
         border-bottom: 2px solid var(--google-grey-300);
         display: flex;
         flex: 0;
-        min-height: 1em;
+        margin-top: 2px;
+        min-height: calc(20/13 * 1em);
         padding-bottom: 8px;
       }
 
diff --git a/chrome/browser/resources/print_preview/new/link_container.html b/chrome/browser/resources/print_preview/new/link_container.html
index 2a811fb..710b1c0 100644
--- a/chrome/browser/resources/print_preview/new/link_container.html
+++ b/chrome/browser/resources/print_preview/new/link_container.html
@@ -9,6 +9,10 @@
 <dom-module id="print-preview-link-container">
   <template>
     <style include="print-preview-shared throbber cr-hidden-style">
+      :host([disabled]) {
+        pointer-events: none;
+      }
+
       .throbber {
         margin: 8px;
         min-height: 16px;
diff --git a/chrome/browser/resources/print_preview/new/pages_settings.html b/chrome/browser/resources/print_preview/new/pages_settings.html
index 2d20d0ba..b6ec296 100644
--- a/chrome/browser/resources/print_preview/new/pages_settings.html
+++ b/chrome/browser/resources/print_preview/new/pages_settings.html
@@ -31,6 +31,7 @@
 
       #pageSettingsCustomInput {
         cursor: default;
+        height: 100%;
       }
     </style>
     <print-preview-settings-section
diff --git a/chrome/browser/resources/print_preview/new/pages_settings.js b/chrome/browser/resources/print_preview/new/pages_settings.js
index 660c9e48..2db57211 100644
--- a/chrome/browser/resources/print_preview/new/pages_settings.js
+++ b/chrome/browser/resources/print_preview/new/pages_settings.js
@@ -139,7 +139,14 @@
         this.onRangeChange_();
         return this.pagesToPrint_;
       }
+
       const limits = range.split('-');
+      if (limits.length > 2) {
+        this.errorState_ = PagesInputErrorState.INVALID_SYNTAX;
+        this.onRangeChange_();
+        return this.pagesToPrint_;
+      }
+
       let min = Number.parseInt(limits[0], 10);
       if ((limits[0].length > 0 && Number.isNaN(min)) || min < 1) {
         this.errorState_ = PagesInputErrorState.INVALID_SYNTAX;
diff --git a/chrome/browser/safe_browsing/download_protection/download_feedback.cc b/chrome/browser/safe_browsing/download_protection/download_feedback.cc
index 3db44bb..421dcb5 100644
--- a/chrome/browser/safe_browsing/download_protection/download_feedback.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_feedback.cc
@@ -21,16 +21,16 @@
 
 // This enum is used by histograms.  Do not change the ordering or remove items.
 enum UploadResultType {
-  UPLOAD_SUCCESS,
-  UPLOAD_CANCELLED,
-  UPLOAD_METADATA_NET_ERROR,
-  UPLOAD_METADATA_RESPONSE_ERROR,
-  UPLOAD_FILE_NET_ERROR,
-  UPLOAD_FILE_RESPONSE_ERROR,
-  UPLOAD_COMPLETE_RESPONSE_ERROR,
+  UPLOAD_SUCCESS = 0,
+  UPLOAD_CANCELLED = 1,
+  UPLOAD_METADATA_NET_ERROR = 2,
+  UPLOAD_METADATA_RESPONSE_ERROR = 3,
+  UPLOAD_FILE_NET_ERROR = 4,
+  UPLOAD_FILE_RESPONSE_ERROR = 5,
+  UPLOAD_COMPLETE_RESPONSE_ERROR = 6,
   // Memory space for histograms is determined by the max.
   // ALWAYS ADD NEW VALUES BEFORE THIS ONE.
-  UPLOAD_RESULT_MAX
+  UPLOAD_RESULT_MAX = 7
 };
 
 // Handles the uploading of a single downloaded binary to the safebrowsing
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 89a6656..e9fdc24f1 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.cc
@@ -507,4 +507,17 @@
           username);
 }
 
+bool DownloadProtectionService::MaybeBeginFeedbackForDownload(
+    Profile* profile,
+    download::DownloadItem* download,
+    DownloadCommands::Command download_command) {
+  PrefService* prefs = profile->GetPrefs();
+  if (!profile->IsOffTheRecord() && ExtendedReportingPrefExists(*prefs) &&
+      IsExtendedReportingEnabled(*prefs)) {
+    feedback_service_->BeginFeedbackForDownload(download, download_command);
+    return true;
+  }
+  return false;
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service.h b/chrome/browser/safe_browsing/download_protection/download_protection_service.h
index 2b54a1c..dffff24 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service.h
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service.h
@@ -23,6 +23,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/supports_user_data.h"
+#include "chrome/browser/download/download_commands.h"
 #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
@@ -121,9 +122,12 @@
     return download_request_timeout_ms_;
   }
 
-  DownloadFeedbackService* feedback_service() {
-    return feedback_service_.get();
-  }
+  // Checks the user permissions, and submits the downloaded file if
+  // appropriate. Returns whether the submission was successful.
+  bool MaybeBeginFeedbackForDownload(
+      Profile* profile,
+      download::DownloadItem* download,
+      DownloadCommands::Command download_command);
 
   // Registers a callback that will be run when a ClientDownloadRequest has
   // been formed.
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
index c14cc16..667767e 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -2639,6 +2639,22 @@
   EXPECT_TRUE(IsResult(DownloadCheckResult::WHITELISTED_BY_POLICY));
 }
 
+TEST_F(DownloadProtectionServiceTest, CheckOffTheRecordDoesNotSendFeedback) {
+  NiceMockDownloadItem item;
+  EXPECT_FALSE(download_service_->MaybeBeginFeedbackForDownload(
+      profile_->GetOffTheRecordProfile(), &item, DownloadCommands::KEEP));
+}
+
+TEST_F(DownloadProtectionServiceTest,
+       CheckNotExtendedReportedDisabledDoesNotSendFeedback) {
+  PrefService* prefs = profile_->GetPrefs();
+  prefs->SetBoolean(GetExtendedReportingPrefName(*prefs), false);
+
+  NiceMockDownloadItem item;
+  EXPECT_FALSE(download_service_->MaybeBeginFeedbackForDownload(
+      profile_.get(), &item, DownloadCommands::KEEP));
+}
+
 // ------------ class DownloadProtectionServiceFlagTest ----------------
 class DownloadProtectionServiceFlagTest : public DownloadProtectionServiceTest {
  protected:
diff --git a/chrome/browser/search/instant_service.cc b/chrome/browser/search/instant_service.cc
index 406066b..d0831ee 100644
--- a/chrome/browser/search/instant_service.cc
+++ b/chrome/browser/search/instant_service.cc
@@ -85,23 +85,41 @@
   return defaults;
 }
 
-base::FilePath GetLocalFilePath() {
+void CopyFileToProfilePath(const base::FilePath& from_path,
+                           const base::FilePath& profile_path) {
+  base::CopyFile(from_path,
+                 profile_path.AppendASCII(
+                     chrome::kChromeSearchLocalNtpBackgroundFilename));
+}
+
+void RemoveLocalBackgroundImageCopy(const base::FilePath& profile_path) {
+  base::DeleteFile(
+      profile_path.AppendASCII(chrome::kChromeSearchLocalNtpBackgroundFilename),
+      false);
+}
+
+// In some cases (Sync, upgrading versions) its necessary to check if the file
+// actually exists and is in the correct location.
+bool CheckLocalBackgroundImageExists(const base::FilePath& profile_path) {
   base::FilePath user_data_dir;
   base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-  return user_data_dir.AppendASCII(
+  base::FilePath profile_image =
+      profile_path.AppendASCII(chrome::kChromeSearchLocalNtpBackgroundFilename);
+  base::FilePath user_data_image = user_data_dir.AppendASCII(
       chrome::kChromeSearchLocalNtpBackgroundFilename);
-}
 
-void CopyFileToProfilePath(const base::FilePath& from_path) {
-  base::CopyFile(from_path, GetLocalFilePath());
-}
+  if (base::PathExists(profile_image))
+    return true;
 
-void RemoveLocalBackgroundImageCopy() {
-  base::DeleteFile(GetLocalFilePath(), false);
-}
+  // The image was originally stored in the user data dir, it needs to be moved
+  // to the profile path if it's still there.
+  if (base::PathExists(user_data_image)) {
+    base::CopyFile(user_data_image, profile_image);
+    base::DeleteFile(user_data_image, false);
+    return true;
+  }
 
-bool CheckLocalBackgroundImageExists() {
-  return base::PathExists(GetLocalFilePath());
+  return false;
 }
 
 bool IsLocalFileUrl(GURL url) {
@@ -366,9 +384,9 @@
     const std::string& attribution_line_2,
     const GURL& action_url) {
   pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, false);
-  base::PostTaskWithTraits(FROM_HERE,
-                           {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
-                           base::BindOnce(&RemoveLocalBackgroundImageCopy));
+  base::PostTaskWithTraits(
+      FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
+      base::BindOnce(&RemoveLocalBackgroundImageCopy, profile_->GetPath()));
 
   if (background_url.is_valid()) {
     base::DictionaryValue background_info = GetBackgroundInfoAsDict(
@@ -395,7 +413,7 @@
 void InstantService::SelectLocalBackgroundImage(const base::FilePath& path) {
   base::PostTaskWithTraitsAndReply(
       FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
-      base::BindOnce(&CopyFileToProfilePath, path),
+      base::BindOnce(&CopyFileToProfilePath, path, profile_->GetPath()),
       base::BindOnce(&InstantService::SetBackgroundToLocalResource,
                      weak_ptr_factory_.GetWeakPtr()));
 }
@@ -644,7 +662,7 @@
       background_local_to_device_pref->IsDefaultValue()) {
     base::PostTaskWithTraitsAndReplyWithResult(
         FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
-        base::BindOnce(&CheckLocalBackgroundImageExists),
+        base::BindOnce(&CheckLocalBackgroundImageExists, profile_->GetPath()),
         base::BindOnce(
             &InstantService::ApplyCustomBackgroundThemeInfoFromLocalFile,
             weak_ptr_factory_.GetWeakPtr()));
@@ -717,9 +735,9 @@
 void InstantService::ResetCustomBackgroundThemeInfo() {
   pref_service_->ClearPref(prefs::kNtpCustomBackgroundDict);
   pref_service_->SetBoolean(prefs::kNtpCustomBackgroundLocalToDevice, false);
-  base::PostTaskWithTraits(FROM_HERE,
-                           {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
-                           base::BindOnce(&RemoveLocalBackgroundImageCopy));
+  base::PostTaskWithTraits(
+      FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
+      base::BindOnce(&RemoveLocalBackgroundImageCopy, profile_->GetPath()));
 
   FallbackToDefaultThemeInfo();
 }
diff --git a/chrome/browser/search/instant_service_unittest.cc b/chrome/browser/search/instant_service_unittest.cc
index 3c73e87..4e6112e 100644
--- a/chrome/browser/search/instant_service_unittest.cc
+++ b/chrome/browser/search/instant_service_unittest.cc
@@ -188,10 +188,9 @@
        LocalBackgroundImageCopyCreated) {
   const GURL kUrl("chrome-search://local-ntp/background.jpg");
 
-  base::FilePath user_data_dir;
-  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-  base::FilePath path(user_data_dir.AppendASCII("test_file"));
-  base::FilePath copy_path(user_data_dir.AppendASCII(
+  base::FilePath profile_path = profile()->GetPath();
+  base::FilePath path(profile_path.AppendASCII("test_file"));
+  base::FilePath copy_path(profile_path.AppendASCII(
       chrome::kChromeSearchLocalNtpBackgroundFilename));
 
   base::WriteFile(path, "background_image", 16);
@@ -209,9 +208,8 @@
 
 TEST_F(InstantServiceTestCustomBackgroundsEnabled,
        ChangingSearchProviderRemovesLocalBackgroundImageCopy) {
-  base::FilePath user_data_dir;
-  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-  base::FilePath path(user_data_dir.AppendASCII(
+  base::FilePath profile_path = profile()->GetPath();
+  base::FilePath path(profile_path.AppendASCII(
       chrome::kChromeSearchLocalNtpBackgroundFilename));
 
   base::WriteFile(path, "background_image", 16);
@@ -232,9 +230,8 @@
        SettingUrlRemovesLocalBackgroundImageCopy) {
   const GURL kUrl("https://www.foo.com");
 
-  base::FilePath user_data_dir;
-  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-  base::FilePath path(user_data_dir.AppendASCII(
+  base::FilePath profile_path = profile()->GetPath();
+  base::FilePath path(profile_path.AppendASCII(
       chrome::kChromeSearchLocalNtpBackgroundFilename));
 
   base::WriteFile(path, "background_image", 16);
@@ -334,9 +331,8 @@
   sync_preferences::TestingPrefServiceSyncable* pref_service =
       profile()->GetTestingPrefService();
 
-  base::FilePath user_data_dir;
-  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-  base::FilePath path(user_data_dir.AppendASCII(
+  base::FilePath profile_path = profile()->GetPath();
+  base::FilePath path(profile_path.AppendASCII(
       chrome::kChromeSearchLocalNtpBackgroundFilename));
   base::WriteFile(path, "background_image", 16);
   base::TaskScheduler::GetInstance()->FlushForTesting();
@@ -368,3 +364,31 @@
   ThemeBackgroundInfo* theme_info = instant_service_->GetThemeInfoForTesting();
   EXPECT_EQ(kUrl, theme_info->custom_background_url);
 }
+
+TEST_F(InstantServiceTestCustomBackgroundsEnabled,
+       LocalFileCopiedToProfileDirectory) {
+  const GURL kUrl("chrome-search://local-ntp/background.jpg?123456789");
+
+  sync_preferences::TestingPrefServiceSyncable* pref_service =
+      profile()->GetTestingPrefService();
+
+  base::FilePath user_data_dir;
+  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
+  base::FilePath old_path(user_data_dir.AppendASCII(
+      chrome::kChromeSearchLocalNtpBackgroundFilename));
+  base::FilePath new_path(profile()->GetPath().AppendASCII(
+      chrome::kChromeSearchLocalNtpBackgroundFilename));
+  base::WriteFile(old_path, "background_image", 16);
+  base::TaskScheduler::GetInstance()->FlushForTesting();
+
+  pref_service->SetUserPref(
+      prefs::kNtpCustomBackgroundDict,
+      std::make_unique<base::Value>(GetBackgroundInfoAsDict(kUrl)));
+  thread_bundle()->RunUntilIdle();
+
+  ThemeBackgroundInfo* theme_info = instant_service_->GetThemeInfoForTesting();
+  EXPECT_EQ(kUrl, theme_info->custom_background_url);
+
+  EXPECT_FALSE(base::PathExists(old_path));
+  EXPECT_TRUE(base::PathExists(new_path));
+}
diff --git a/chrome/browser/search/local_ntp_source.cc b/chrome/browser/search/local_ntp_source.cc
index 55fb3a2..f22d405 100644
--- a/chrome/browser/search/local_ntp_source.cc
+++ b/chrome/browser/search/local_ntp_source.cc
@@ -267,13 +267,11 @@
                             SkColorGetB(background_color));
 }
 
-std::string ReadBackgroundImageData() {
+std::string ReadBackgroundImageData(const base::FilePath& profile_path) {
   std::string data_string;
-  base::FilePath user_data_dir;
-  base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-  base::ReadFileToString(user_data_dir.AppendASCII(
-                             chrome::kChromeSearchLocalNtpBackgroundFilename),
-                         &data_string);
+  base::ReadFileToString(
+      profile_path.AppendASCII(chrome::kChromeSearchLocalNtpBackgroundFilename),
+      &data_string);
   return data_string;
 }
 
@@ -718,7 +716,7 @@
   if (stripped_path == chrome::kChromeSearchLocalNtpBackgroundFilename) {
     base::PostTaskWithTraitsAndReplyWithResult(
         FROM_HERE, {base::TaskPriority::USER_VISIBLE, base::MayBlock()},
-        base::BindOnce(&ReadBackgroundImageData),
+        base::BindOnce(&ReadBackgroundImageData, profile_->GetPath()),
         base::BindOnce(&ServeBackgroundImageData, callback));
     return;
   }
diff --git a/chrome/browser/sync/chrome_sync_client.cc b/chrome/browser/sync/chrome_sync_client.cc
index b1f67841..640ee8f 100644
--- a/chrome/browser/sync/chrome_sync_client.cc
+++ b/chrome/browser/sync/chrome_sync_client.cc
@@ -28,24 +28,20 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/sync/bookmark_sync_service_factory.h"
-#include "chrome/browser/sync/glue/sync_start_util.h"
 #include "chrome/browser/sync/glue/theme_data_type_controller.h"
 #include "chrome/browser/sync/model_type_store_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router.h"
-#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h"
+#include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/browser/sync/user_event_service_factory.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/themes/theme_syncable_service.h"
-#include "chrome/browser/ui/sync/browser_synced_window_delegates_getter.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "chrome/browser/web_data_service_factory.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
 #include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_sync_bridge.h"
 #include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
@@ -70,7 +66,6 @@
 #include "components/spellcheck/spellcheck_buildflags.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/report_unrecoverable_error.h"
-#include "components/sync/device_info/local_device_info_provider.h"
 #include "components/sync/driver/async_directory_type_controller.h"
 #include "components/sync/driver/sync_api_component_factory.h"
 #include "components/sync/driver/sync_util.h"
@@ -81,8 +76,7 @@
 #include "components/sync_bookmarks/bookmark_sync_service.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/sync_sessions/favicon_cache.h"
-#include "components/sync_sessions/session_sync_bridge.h"
-#include "components/sync_sessions/sync_sessions_client.h"
+#include "components/sync_sessions/session_sync_service.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/api/storage/backend_task_runner.h"
@@ -116,10 +110,6 @@
 #include "chrome/browser/spellchecker/spellcheck_service.h"
 #endif  // BUILDFLAG(ENABLE_SPELLCHECK)
 
-#if defined(OS_ANDROID)
-#include "chrome/browser/sync/glue/synced_window_delegates_getter_android.h"
-#endif  // defined(OS_ANDROID)
-
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/printing/printers_sync_bridge.h"
@@ -158,78 +148,7 @@
 
 }  // namespace
 
-// Chrome implementation of SyncSessionsClient. Needs to be in a separate class
-// due to possible multiple inheritance issues, wherein ChromeSyncClient might
-// inherit from other interfaces with same methods.
-class SyncSessionsClientImpl : public sync_sessions::SyncSessionsClient {
- public:
-  explicit SyncSessionsClientImpl(Profile* profile) : profile_(profile) {
-    window_delegates_getter_.reset(
-#if defined(OS_ANDROID)
-        // Android doesn't have multi-profile support, so no need to pass the
-        // profile in.
-        new SyncedWindowDelegatesGetterAndroid());
-#else   // defined(OS_ANDROID)
-        new browser_sync::BrowserSyncedWindowDelegatesGetter(profile));
-#endif  // defined(OS_ANDROID)
-  }
-  ~SyncSessionsClientImpl() override {}
-
-  // SyncSessionsClient implementation.
-  favicon::FaviconService* GetFaviconService() override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    return FaviconServiceFactory::GetForProfile(
-        profile_, ServiceAccessType::IMPLICIT_ACCESS);
-  }
-  history::HistoryService* GetHistoryService() override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    return HistoryServiceFactory::GetForProfile(
-        profile_, ServiceAccessType::EXPLICIT_ACCESS);
-  }
-  const syncer::DeviceInfo* GetLocalDeviceInfo() override {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    return ProfileSyncServiceFactory::GetForProfile(profile_)
-        ->GetLocalDeviceInfoProvider()
-        ->GetLocalDeviceInfo();
-  }
-  bool ShouldSyncURL(const GURL& url) const override {
-    if (url == chrome::kChromeUIHistoryURL) {
-      // The history page is treated specially as we want it to trigger syncable
-      // events for UI purposes.
-      return true;
-    }
-    return url.is_valid() && !url.SchemeIs(content::kChromeUIScheme) &&
-           !url.SchemeIs(chrome::kChromeNativeScheme) && !url.SchemeIsFile();
-  }
-
-  sync_sessions::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter()
-      override {
-    return window_delegates_getter_.get();
-  }
-
-  sync_sessions::LocalSessionEventRouter* GetLocalSessionEventRouter()
-      override {
-    syncer::SyncableService::StartSyncFlare flare(
-        sync_start_util::GetFlareForSyncableService(profile_->GetPath()));
-    sync_sessions::SyncSessionsWebContentsRouter* router =
-        sync_sessions::SyncSessionsWebContentsRouterFactory::GetForProfile(
-            profile_);
-    router->InjectStartSyncFlare(flare);
-    return router;
-  }
-
- private:
-  Profile* profile_;
-  std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter>
-      window_delegates_getter_;
-
-  DISALLOW_COPY_AND_ASSIGN(SyncSessionsClientImpl);
-};
-
-ChromeSyncClient::ChromeSyncClient(Profile* profile)
-    : profile_(profile),
-      sync_sessions_client_(std::make_unique<SyncSessionsClientImpl>(profile)) {
-}
+ChromeSyncClient::ChromeSyncClient(Profile* profile) : profile_(profile) {}
 
 ChromeSyncClient::~ChromeSyncClient() {
 }
@@ -333,6 +252,11 @@
       profile_, ServiceAccessType::EXPLICIT_ACCESS);
 }
 
+sync_sessions::SessionSyncService* ChromeSyncClient::GetSessionSyncService() {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  return SessionSyncServiceFactory::GetForProfile(profile_);
+}
+
 bool ChromeSyncClient::HasPasswordStore() {
   return password_store_ != nullptr;
 }
@@ -468,10 +392,6 @@
   return extensions_activity_monitor_.GetExtensionsActivity();
 }
 
-sync_sessions::SyncSessionsClient* ChromeSyncClient::GetSyncSessionsClient() {
-  return sync_sessions_client_.get();
-}
-
 base::WeakPtr<syncer::SyncableService>
 ChromeSyncClient::GetSyncableServiceForType(syncer::ModelType type) {
   if (!profile_) {  // For tests.
@@ -553,7 +473,7 @@
     case syncer::FAVICON_IMAGES:
     case syncer::FAVICON_TRACKING: {
       sync_sessions::FaviconCache* favicons =
-          ProfileSyncServiceFactory::GetForProfile(profile_)->GetFaviconCache();
+          SessionSyncServiceFactory::GetForProfile(profile_)->GetFaviconCache();
       return favicons ? favicons->AsWeakPtr()
                       : base::WeakPtr<syncer::SyncableService>();
     }
@@ -573,8 +493,9 @@
     }
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
     case syncer::SESSIONS: {
-      return ProfileSyncServiceFactory::GetForProfile(profile_)->
-          GetSessionsSyncableService()->AsWeakPtr();
+      return SessionSyncServiceFactory::GetForProfile(profile_)
+          ->GetSyncableService()
+          ->AsWeakPtr();
     }
     case syncer::PASSWORDS: {
       return password_store_.get()
@@ -624,10 +545,6 @@
           ->GetSyncBridge()
           ->change_processor()
           ->GetControllerDelegate();
-    case syncer::SESSIONS: {
-      return ProfileSyncServiceFactory::GetForProfile(profile_)
-          ->GetSessionSyncControllerDelegate();
-    }
 
     // We don't exercise this function for certain datatypes, because their
     // controllers get the delegate elsewhere.
@@ -636,6 +553,7 @@
     case syncer::AUTOFILL_WALLET_DATA:
     case syncer::AUTOFILL_WALLET_METADATA:
     case syncer::BOOKMARKS:
+    case syncer::SESSIONS:
     case syncer::TYPED_URLS:
       NOTREACHED();
       return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
diff --git a/chrome/browser/sync/chrome_sync_client.h b/chrome/browser/sync/chrome_sync_client.h
index 1baeb45..66674be 100644
--- a/chrome/browser/sync/chrome_sync_client.h
+++ b/chrome/browser/sync/chrome_sync_client.h
@@ -47,6 +47,7 @@
   bookmarks::BookmarkModel* GetBookmarkModel() override;
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
+  sync_sessions::SessionSyncService* GetSessionSyncService() override;
   bool HasPasswordStore() override;
   base::Closure GetPasswordStateChangedCallback() override;
   syncer::DataTypeController::TypeVector CreateDataTypeControllers(
@@ -55,7 +56,6 @@
   invalidation::InvalidationService* GetInvalidationService() override;
   BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
   scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
-  sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override;
   base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
       syncer::ModelType type) override;
   base::WeakPtr<syncer::ModelTypeControllerDelegate>
@@ -89,8 +89,6 @@
   // The task runner for the |web_data_service_|, if any.
   scoped_refptr<base::SingleThreadTaskRunner> web_data_service_thread_;
 
-  std::unique_ptr<sync_sessions::SyncSessionsClient> sync_sessions_client_;
-
   // Generates and monitors the ExtensionsActivity object used by sync.
   ExtensionsActivityMonitor extensions_activity_monitor_;
 
diff --git a/chrome/browser/sync/chrome_sync_client_unittest.cc b/chrome/browser/sync/chrome_sync_client_unittest.cc
deleted file mode 100644
index fa48932..0000000
--- a/chrome/browser/sync/chrome_sync_client_unittest.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/sync/chrome_sync_client.h"
-
-#include <memory>
-#include <string>
-
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/sync/driver/sync_api_component_factory.h"
-#include "components/sync_sessions/sync_sessions_client.h"
-#include "content/public/test/test_browser_thread_bundle.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace browser_sync {
-
-namespace {
-
-const char kValidUrl[] = "http://www.example.com";
-const char kInvalidUrl[] = "invalid.url";
-
-class ChromeSyncClientTest : public testing::Test {
- public:
-  ChromeSyncClientTest()
-      : profile_(new TestingProfile()),
-        sync_client_(new ChromeSyncClient(profile_.get())) {}
-  ~ChromeSyncClientTest() override {}
-
-  ChromeSyncClient* sync_client() { return sync_client_.get(); }
-
- private:
-  content::TestBrowserThreadBundle thread_bundle_;
-  std::unique_ptr<TestingProfile> profile_;
-  std::unique_ptr<ChromeSyncClient> sync_client_;
-};
-
-TEST_F(ChromeSyncClientTest, ShouldSyncURL) {
-  EXPECT_TRUE(
-      sync_client()->GetSyncSessionsClient()->ShouldSyncURL(GURL(kValidUrl)));
-  EXPECT_TRUE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL(
-      GURL("other://anything")));
-  EXPECT_TRUE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL(
-      GURL("chrome-other://anything")));
-
-  EXPECT_FALSE(
-      sync_client()->GetSyncSessionsClient()->ShouldSyncURL(GURL(kInvalidUrl)));
-  EXPECT_FALSE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL(
-      GURL("file://anything")));
-  EXPECT_FALSE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL(
-      GURL("chrome://anything")));
-  EXPECT_FALSE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL(
-      GURL("chrome-native://anything")));
-
-  EXPECT_TRUE(sync_client()->GetSyncSessionsClient()->ShouldSyncURL(
-      GURL(chrome::kChromeUIHistoryURL)));
-}
-
-}  // namespace
-
-}  // namespace browser_sync
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc
index 33f1f744..e93f595e 100644
--- a/chrome/browser/sync/profile_sync_service_android.cc
+++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -21,6 +21,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/browser/sync/sync_ui_util.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/grit/generated_resources.h"
@@ -34,6 +35,7 @@
 #include "components/sync/driver/sync_service_utils.h"
 #include "components/sync/engine/net/network_resources.h"
 #include "components/sync/syncable/read_transaction.h"
+#include "components/sync_sessions/session_sync_service.h"
 #include "components/unified_consent/url_keyed_data_collection_consent_helper.h"
 #include "content/public/browser/browser_thread.h"
 #include "google/cacheinvalidation/types.pb.h"
@@ -410,7 +412,8 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(profile_);
   std::string machine_tag = ConvertJavaStringToUTF8(env, tag);
-  sync_prefs_->SetSyncSessionsGUID(machine_tag);
+  SessionSyncServiceFactory::GetForProfile(profile_)->SetSyncSessionsGUID(
+      machine_tag);
 }
 
 jboolean ProfileSyncServiceAndroid::HasKeepEverythingSynced(
diff --git a/chrome/browser/sync/profile_sync_service_factory.cc b/chrome/browser/sync/profile_sync_service_factory.cc
index 4e283fb..8e487773 100644
--- a/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/chrome/browser/sync/profile_sync_service_factory.cc
@@ -34,7 +34,8 @@
 #include "chrome/browser/spellchecker/spellcheck_factory.h"
 #include "chrome/browser/sync/bookmark_sync_service_factory.h"
 #include "chrome/browser/sync/chrome_sync_client.h"
-#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h"
+#include "chrome/browser/sync/model_type_store_service_factory.h"
+#include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/browser/sync/user_event_service_factory.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/undo/bookmark_undo_service_factory.h"
@@ -130,7 +131,8 @@
         BrowserContextDependencyManager::GetInstance()) {
   // The ProfileSyncService depends on various SyncableServices being around
   // when it is shut down.  Specify those dependencies here to build the proper
-  // destruction order.
+  // destruction order. Note that some of the dependencies are listed here but
+  // actually plumbed in ChromeSyncClient, which this factory constructs.
   DependsOn(AboutSigninInternalsFactory::GetInstance());
   DependsOn(autofill::PersonalDataManagerFactory::GetInstance());
   DependsOn(BookmarkModelFactory::GetInstance());
@@ -151,12 +153,13 @@
   DependsOn(invalidation::DeprecatedProfileInvalidationProviderFactory::
                 GetInstance());
   DependsOn(invalidation::ProfileInvalidationProviderFactory::GetInstance());
+  DependsOn(ModelTypeStoreServiceFactory::GetInstance());
   DependsOn(PasswordStoreFactory::GetInstance());
   DependsOn(SpellcheckServiceFactory::GetInstance());
 #if BUILDFLAG(ENABLE_SUPERVISED_USERS)
   DependsOn(SupervisedUserSettingsServiceFactory::GetInstance());
 #endif  // BUILDFLAG(ENABLE_SUPERVISED_USERS)
-  DependsOn(sync_sessions::SyncSessionsWebContentsRouterFactory::GetInstance());
+  DependsOn(SessionSyncServiceFactory::GetInstance());
   DependsOn(TemplateURLServiceFactory::GetInstance());
   DependsOn(WebDataServiceFactory::GetInstance());
 #if BUILDFLAG(ENABLE_EXTENSIONS)
@@ -167,12 +170,6 @@
   DependsOn(chromeos::SyncedPrintersManagerFactory::GetInstance());
   DependsOn(sync_wifi::WifiCredentialSyncableServiceFactory::GetInstance());
 #endif  // defined(OS_CHROMEOS)
-
-  // The following have not been converted to KeyedServices yet,
-  // and for now they are explicitly destroyed after the
-  // BrowserContextDependencyManager is told to DestroyBrowserContextServices,
-  // so they will be around when the ProfileSyncService is destroyed.
-
 }
 
 ProfileSyncServiceFactory::~ProfileSyncServiceFactory() {
diff --git a/chrome/browser/sync/session_sync_service_factory.cc b/chrome/browser/sync/session_sync_service_factory.cc
new file mode 100644
index 0000000..f847412
--- /dev/null
+++ b/chrome/browser/sync/session_sync_service_factory.cc
@@ -0,0 +1,169 @@
+// 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/sync/session_sync_service_factory.h"
+
+#include "base/memory/singleton.h"
+#include "build/build_config.h"
+#include "chrome/browser/favicon/favicon_service_factory.h"
+#include "chrome/browser/history/history_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sync/glue/sync_start_util.h"
+#include "chrome/browser/sync/model_type_store_service_factory.h"
+#include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router.h"
+#include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h"
+#include "chrome/browser/ui/sync/browser_synced_window_delegates_getter.h"
+#include "chrome/common/channel_info.h"
+#include "chrome/common/url_constants.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/sync/device_info/local_device_info_provider.h"
+#include "components/sync/model/model_type_store_service.h"
+#include "components/sync_sessions/session_sync_prefs.h"
+#include "components/sync_sessions/session_sync_service.h"
+#include "components/sync_sessions/sync_sessions_client.h"
+
+#if defined(OS_ANDROID)
+#include "chrome/browser/sync/glue/synced_window_delegates_getter_android.h"
+#endif  // defined(OS_ANDROID)
+
+namespace {
+
+bool ShouldSyncURLImpl(const GURL& url) {
+  if (url == chrome::kChromeUIHistoryURL) {
+    // Whitelist the chrome history page, home for "Tabs from other devices", so
+    // it can trigger starting up the sync engine.
+    return true;
+  }
+  return url.is_valid() && !url.SchemeIs(content::kChromeUIScheme) &&
+         !url.SchemeIs(chrome::kChromeNativeScheme) && !url.SchemeIsFile();
+}
+
+// Chrome implementation of SyncSessionsClient.
+class SyncSessionsClientImpl : public sync_sessions::SyncSessionsClient {
+ public:
+  explicit SyncSessionsClientImpl(Profile* profile)
+      : profile_(profile), session_sync_prefs_(profile->GetPrefs()) {
+    window_delegates_getter_ =
+#if defined(OS_ANDROID)
+        // Android doesn't have multi-profile support, so no need to pass the
+        // profile in.
+        std::make_unique<browser_sync::SyncedWindowDelegatesGetterAndroid>();
+#else   // defined(OS_ANDROID)
+        std::make_unique<browser_sync::BrowserSyncedWindowDelegatesGetter>(
+            profile);
+#endif  // defined(OS_ANDROID)
+  }
+
+  ~SyncSessionsClientImpl() override {}
+
+  // SyncSessionsClient implementation.
+  favicon::FaviconService* GetFaviconService() override {
+    return FaviconServiceFactory::GetForProfile(
+        profile_, ServiceAccessType::IMPLICIT_ACCESS);
+  }
+
+  history::HistoryService* GetHistoryService() override {
+    return HistoryServiceFactory::GetForProfile(
+        profile_, ServiceAccessType::EXPLICIT_ACCESS);
+  }
+
+  sync_sessions::SessionSyncPrefs* GetSessionSyncPrefs() override {
+    return &session_sync_prefs_;
+  }
+
+  syncer::RepeatingModelTypeStoreFactory GetStoreFactory() override {
+    return ModelTypeStoreServiceFactory::GetForProfile(profile_)
+        ->GetStoreFactory();
+  }
+
+  const syncer::DeviceInfo* GetLocalDeviceInfo() override {
+    // Avoid creating ProfileSyncService if there wasn't one, to avoid
+    // dependency cycles among keyed services.
+    if (!ProfileSyncServiceFactory::HasProfileSyncService(profile_)) {
+      return nullptr;
+    }
+    return ProfileSyncServiceFactory::GetForProfile(profile_)
+        ->GetLocalDeviceInfoProvider()
+        ->GetLocalDeviceInfo();
+  }
+
+  bool ShouldSyncURL(const GURL& url) const override {
+    return ShouldSyncURLImpl(url);
+  }
+
+  sync_sessions::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter()
+      override {
+    return window_delegates_getter_.get();
+  }
+
+  sync_sessions::LocalSessionEventRouter* GetLocalSessionEventRouter()
+      override {
+    syncer::SyncableService::StartSyncFlare flare(
+        sync_start_util::GetFlareForSyncableService(profile_->GetPath()));
+    sync_sessions::SyncSessionsWebContentsRouter* router =
+        sync_sessions::SyncSessionsWebContentsRouterFactory::GetForProfile(
+            profile_);
+    // TODO(mastiz): Injecting a start flare as a side effect of what seems to
+    // be a getter is error-prone. In fact, we seem to call this function very
+    // early for the USS implementation.
+    router->InjectStartSyncFlare(flare);
+    return router;
+  }
+
+  void NotifyForeignSessionUpdated() override {
+    if (!ProfileSyncServiceFactory::HasProfileSyncService(profile_)) {
+      return;
+    }
+    ProfileSyncServiceFactory::GetForProfile(profile_)
+        ->NotifyForeignSessionUpdated();
+  }
+
+ private:
+  Profile* const profile_;
+  std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter>
+      window_delegates_getter_;
+  sync_sessions::SessionSyncPrefs session_sync_prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(SyncSessionsClientImpl);
+};
+
+}  // namespace
+
+// static
+sync_sessions::SessionSyncService* SessionSyncServiceFactory::GetForProfile(
+    Profile* profile) {
+  return static_cast<sync_sessions::SessionSyncService*>(
+      GetInstance()->GetServiceForBrowserContext(profile, true));
+}
+
+// static
+SessionSyncServiceFactory* SessionSyncServiceFactory::GetInstance() {
+  return base::Singleton<SessionSyncServiceFactory>::get();
+}
+
+// static
+bool SessionSyncServiceFactory::ShouldSyncURLForTesting(const GURL& url) {
+  return ShouldSyncURLImpl(url);
+}
+
+SessionSyncServiceFactory::SessionSyncServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "SessionSyncService",
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(FaviconServiceFactory::GetInstance());
+  DependsOn(HistoryServiceFactory::GetInstance());
+  DependsOn(ModelTypeStoreServiceFactory::GetInstance());
+  DependsOn(sync_sessions::SyncSessionsWebContentsRouterFactory::GetInstance());
+}
+
+SessionSyncServiceFactory::~SessionSyncServiceFactory() {}
+
+KeyedService* SessionSyncServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  Profile* profile = Profile::FromBrowserContext(context);
+  return new sync_sessions::SessionSyncService(
+      chrome::GetChannel(), std::make_unique<SyncSessionsClientImpl>(profile));
+}
diff --git a/chrome/browser/sync/session_sync_service_factory.h b/chrome/browser/sync/session_sync_service_factory.h
new file mode 100644
index 0000000..e31389f
--- /dev/null
+++ b/chrome/browser/sync/session_sync_service_factory.h
@@ -0,0 +1,45 @@
+// 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_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+class GURL;
+class Profile;
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace sync_sessions {
+class SessionSyncService;
+}  // namespace sync_sessions
+
+class SessionSyncServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static sync_sessions::SessionSyncService* GetForProfile(Profile* profile);
+  static SessionSyncServiceFactory* GetInstance();
+
+  static bool ShouldSyncURLForTesting(const GURL& url);
+
+ private:
+  friend struct base::DefaultSingletonTraits<SessionSyncServiceFactory>;
+
+  SessionSyncServiceFactory();
+  ~SessionSyncServiceFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(SessionSyncServiceFactory);
+};
+
+#endif  // CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_
diff --git a/chrome/browser/sync/session_sync_service_factory_unittest.cc b/chrome/browser/sync/session_sync_service_factory_unittest.cc
new file mode 100644
index 0000000..e3a3f41a
--- /dev/null
+++ b/chrome/browser/sync/session_sync_service_factory_unittest.cc
@@ -0,0 +1,37 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/sync/session_sync_service_factory.h"
+
+#include "chrome/common/url_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+
+const char kValidUrl[] = "http://www.example.com";
+const char kInvalidUrl[] = "invalid.url";
+
+TEST(SessionSyncServiceFactoryTest, ShouldSyncURL) {
+  EXPECT_TRUE(
+      SessionSyncServiceFactory::ShouldSyncURLForTesting(GURL(kValidUrl)));
+  EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL("other://anything")));
+  EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL("chrome-other://anything")));
+
+  EXPECT_FALSE(
+      SessionSyncServiceFactory::ShouldSyncURLForTesting(GURL(kInvalidUrl)));
+  EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL("file://anything")));
+  EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL("chrome://anything")));
+  EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL("chrome-native://anything")));
+
+  EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL(chrome::kChromeUIHistoryURL)));
+}
+
+}  // namespace
diff --git a/chrome/browser/sync/user_event_service_factory.cc b/chrome/browser/sync/user_event_service_factory.cc
index cf817ba..901a6595 100644
--- a/chrome/browser/sync/user_event_service_factory.cc
+++ b/chrome/browser/sync/user_event_service_factory.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sync/model_type_store_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/common/channel_info.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
@@ -21,6 +22,7 @@
 #include "components/sync/user_events/no_op_user_event_service.h"
 #include "components/sync/user_events/user_event_service_impl.h"
 #include "components/sync/user_events/user_event_sync_bridge.h"
+#include "components/sync_sessions/session_sync_service.h"
 
 namespace browser_sync {
 
@@ -41,6 +43,7 @@
           "UserEventService",
           BrowserContextDependencyManager::GetInstance()) {
   DependsOn(ModelTypeStoreServiceFactory::GetInstance());
+  DependsOn(SessionSyncServiceFactory::GetInstance());
   // TODO(vitaliii): This is missing
   // DependsOn(ProfileSyncServiceFactory::GetInstance()), which we can't
   // simply add because ProfileSyncServiceFactory itself depends on this
@@ -70,7 +73,7 @@
                               chrome::GetChannel()));
   auto bridge = std::make_unique<syncer::UserEventSyncBridge>(
       std::move(store_factory), std::move(change_processor),
-      sync_service->GetGlobalIdMapper());
+      SessionSyncServiceFactory::GetForProfile(profile)->GetGlobalIdMapper());
   return new syncer::UserEventServiceImpl(sync_service, std::move(bridge));
 }
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 81a63654..0d17497 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -75,10 +75,6 @@
       "cocoa/browser_window_utils.mm",
       "cocoa/bubble_anchor_helper.h",
       "cocoa/bubble_anchor_helper.mm",
-      "cocoa/bubble_combobox.h",
-      "cocoa/bubble_combobox.mm",
-      "cocoa/bubble_view.h",
-      "cocoa/bubble_view.mm",
       "cocoa/certificate_viewer_mac_cocoa.h",
       "cocoa/certificate_viewer_mac_cocoa.mm",
       "cocoa/chrome_browser_window.h",
@@ -109,8 +105,6 @@
       "cocoa/constrained_window/constrained_window_web_dialog_sheet.h",
       "cocoa/constrained_window/constrained_window_web_dialog_sheet.mm",
       "cocoa/create_native_web_modal_manager_cocoa.mm",
-      "cocoa/dev_tools_controller.h",
-      "cocoa/dev_tools_controller.mm",
       "cocoa/drag_util.h",
       "cocoa/drag_util.mm",
       "cocoa/extensions/extension_keybinding_registry_cocoa.h",
@@ -148,14 +142,6 @@
       "cocoa/image_button_cell.mm",
       "cocoa/javascript_app_modal_dialog_cocoa.h",
       "cocoa/javascript_app_modal_dialog_cocoa.mm",
-      "cocoa/location_bar/autocomplete_text_field.h",
-      "cocoa/location_bar/autocomplete_text_field.mm",
-      "cocoa/location_bar/autocomplete_text_field_cell.h",
-      "cocoa/location_bar/autocomplete_text_field_cell.mm",
-      "cocoa/location_bar/autocomplete_text_field_editor.h",
-      "cocoa/location_bar/autocomplete_text_field_editor.mm",
-      "cocoa/location_bar/location_bar_decoration.h",
-      "cocoa/location_bar/location_bar_decoration.mm",
       "cocoa/location_bar/location_bar_view_mac.h",
       "cocoa/location_bar/location_bar_view_mac.mm",
       "cocoa/main_menu_item.h",
@@ -163,16 +149,6 @@
       "cocoa/menu_button.mm",
       "cocoa/nsview_additions.h",
       "cocoa/nsview_additions.mm",
-      "cocoa/omnibox/omnibox_popup_cell.h",
-      "cocoa/omnibox/omnibox_popup_cell.mm",
-      "cocoa/omnibox/omnibox_popup_matrix.h",
-      "cocoa/omnibox/omnibox_popup_matrix.mm",
-      "cocoa/omnibox/omnibox_popup_separator_view.h",
-      "cocoa/omnibox/omnibox_popup_separator_view.mm",
-      "cocoa/omnibox/omnibox_popup_view_mac.h",
-      "cocoa/omnibox/omnibox_popup_view_mac.mm",
-      "cocoa/omnibox/omnibox_view_mac.h",
-      "cocoa/omnibox/omnibox_view_mac.mm",
       "cocoa/rect_path_utils.h",
       "cocoa/rect_path_utils.mm",
       "cocoa/restart_browser.h",
@@ -188,8 +164,6 @@
       "cocoa/ssl_client_certificate_selector_cocoa.h",
       "cocoa/ssl_client_certificate_selector_cocoa.mm",
       "cocoa/spinner_util.h",
-      "cocoa/status_bubble_mac.h",
-      "cocoa/status_bubble_mac.mm",
       "cocoa/styled_text_field.h",
       "cocoa/styled_text_field.mm",
       "cocoa/styled_text_field_cell.h",
@@ -2153,7 +2127,6 @@
       "cocoa/confirm_quit_panel_controller.mm",
       "cocoa/dock_icon.h",
       "cocoa/dock_icon.mm",
-      "cocoa/download/download_started_animation_mac.mm",
       "cocoa/first_run_dialog.h",
       "cocoa/first_run_dialog.mm",
       "cocoa/first_run_dialog_controller.h",
@@ -2595,8 +2568,6 @@
       "views/device_chooser_content_view.cc",
       "views/device_chooser_content_view.h",
       "views/download/download_danger_prompt_views.cc",
-      "views/download/download_feedback_dialog_view.cc",
-      "views/download/download_feedback_dialog_view.h",
       "views/download/download_in_progress_dialog_view.cc",
       "views/download/download_in_progress_dialog_view.h",
       "views/download/download_item_view.cc",
@@ -3684,6 +3655,7 @@
       "//chrome/browser/ui/webui/reset_password:mojo_bindings",
       "//chrome/common/safe_browsing:proto",
       "//components/safe_browsing:csd_proto",
+      "//components/safe_browsing/password_protection:password_protection_metrics_util",
     ]
   }
 
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index 26b5d17..0605c54 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -1221,6 +1221,11 @@
   return window_->GetTopControlsHeight();
 }
 
+bool Browser::DoBrowserControlsShrinkRendererSize(
+    const content::WebContents* contents) const {
+  return window_->DoBrowserControlsShrinkRendererSize(contents);
+}
+
 void Browser::SetTopControlsGestureScrollInProgress(bool in_progress) {
   window_->SetTopControlsGestureScrollInProgress(in_progress);
 }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index b51c713aa..615e1a5 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -473,6 +473,8 @@
   void SetTopControlsShownRatio(content::WebContents* web_contents,
                                 float ratio) override;
   int GetTopControlsHeight() const override;
+  bool DoBrowserControlsShrinkRendererSize(
+      const content::WebContents* contents) const override;
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
   bool CanOverscrollContent() const override;
   bool ShouldPreserveAbortedURLs(content::WebContents* source) override;
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index 43f07ff..25cf05ad 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -120,6 +120,37 @@
   virtual void SetTopControlsShownRatio(content::WebContents* web_contents,
                                         float ratio) = 0;
 
+  // Whether or not the renderer's viewport size should be shrunk by the height
+  // of the browser's top controls.
+  // As top-chrome is slided up or down, we don't actually resize the web
+  // contents (for perf reasons) but we have to do a bunch of adjustments on the
+  // renderer side to make it appear to the user like we're resizing things
+  // smoothly:
+  //
+  // 1) Expose content beyond the web contents rect by expanding the clip.
+  // 2) Push bottom-fixed elements around until we get a resize. As top-chrome
+  //    hides, we push the fixed elements down by an equivalent amount so that
+  //    they appear to stay fixed to the viewport bottom.
+  //
+  // Only when the user releases their finger to finish the scroll do we
+  // actually resize the web contents and clear these adjustments. So web
+  // contents has two possible sizes, viewport filling and shrunk by the top
+  // controls.
+  //
+  // The GetTopControlsHeight is a static number that never changes (as long as
+  // the top-chrome slide with gesture scrolls feature is enabled). To get the
+  // actual "showing" height as the user sees, you multiply this by the shown
+  // ratio. However, it's not enough to know this value, the renderer also needs
+  // to know which direction it should be doing the above-mentioned adjustments.
+  // That's what the DoBrowserControlsShrinkRendererSize bit is for. It tells
+  // the renderer whether it's currently in the "viewport filling" or the
+  // "shrunk by top controls" state.
+  // The returned value should never change while sliding top-chrome is in
+  // progress (either due to an in-progress gesture scroll, or due to a
+  // renderer-initiated animation of the top controls shown ratio).
+  virtual bool DoBrowserControlsShrinkRendererSize(
+      const content::WebContents* contents) const = 0;
+
   // Returns the height of the browser's top controls. This height doesn't
   // change with the current shown ratio above. Renderers will call this to
   // calculate the top-chrome shown ratio from the gesture scroll offset.
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.h b/chrome/browser/ui/cocoa/browser_window_cocoa.h
index d5c965e..74d67ac2 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.h
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.h
@@ -54,6 +54,8 @@
   gfx::NativeWindow GetNativeWindow() const override;
   void SetTopControlsShownRatio(content::WebContents* web_contents,
                                 float ratio) override;
+  bool DoBrowserControlsShrinkRendererSize(
+      const content::WebContents* contents) const override;
   int GetTopControlsHeight() const override;
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
   StatusBubble* GetStatusBubble() override;
diff --git a/chrome/browser/ui/cocoa/browser_window_cocoa.mm b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
index b6ee3a8..2fb2747 100644
--- a/chrome/browser/ui/cocoa/browser_window_cocoa.mm
+++ b/chrome/browser/ui/cocoa/browser_window_cocoa.mm
@@ -39,7 +39,6 @@
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 #import "chrome/browser/ui/cocoa/nsmenuitem_additions.h"
 #include "chrome/browser/ui/cocoa/restart_browser.h"
-#include "chrome/browser/ui/cocoa/status_bubble_mac.h"
 #include "chrome/browser/ui/cocoa/task_manager_mac.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
@@ -247,6 +246,12 @@
   NOTIMPLEMENTED();
 }
 
+bool BrowserWindowCocoa::DoBrowserControlsShrinkRendererSize(
+    const content::WebContents* contents) const {
+  NOTIMPLEMENTED();
+  return false;
+}
+
 int BrowserWindowCocoa::GetTopControlsHeight() const {
   NOTIMPLEMENTED();
   return 0;
@@ -258,7 +263,7 @@
 }
 
 StatusBubble* BrowserWindowCocoa::GetStatusBubble() {
-  return [controller_ statusBubble];
+  return nullptr;
 }
 
 void BrowserWindowCocoa::UpdateTitleBar() {
@@ -409,7 +414,7 @@
 }
 
 PageActionIconContainer* BrowserWindowCocoa::GetPageActionIconContainer() {
-  return [controller_ locationBarBridge];
+  return nullptr;
 }
 
 LocationBar* BrowserWindowCocoa::GetLocationBar() const {
@@ -417,7 +422,6 @@
 }
 
 void BrowserWindowCocoa::SetFocusToLocationBar(bool select_all) {
-  [controller_ focusLocationBar:select_all ? YES : NO];
 }
 
 void BrowserWindowCocoa::UpdateReloadStopState(bool is_loading, bool force) {
@@ -541,10 +545,6 @@
 
 void BrowserWindowCocoa::UserChangedTheme() {
   [controller_ userChangedTheme];
-  LocationBarViewMac* locationBar = [controller_ locationBarBridge];
-  if (locationBar) {
-    locationBar->OnThemeChanged();
-  }
 }
 
 void BrowserWindowCocoa::ShowAppMenu() {
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.h b/chrome/browser/ui/cocoa/browser_window_controller.h
index 7e0ab8f..3ffb675 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller.h
@@ -36,7 +36,6 @@
 class BrowserWindowCocoa;
 @class BrowserWindowFullscreenTransition;
 @class BrowserWindowTouchBarController;
-@class DevToolsController;
 class ExtensionKeybindingRegistryCocoa;
 class ExclusiveAccessController;
 class ExclusiveAccessContext;
@@ -46,7 +45,6 @@
 @class FullscreenWindow;
 class LocationBarViewMac;
 @class OverlayableContentsController;
-class StatusBubbleMac;
 @class TabStripControllerCocoa;
 @class TabStripView;
 @class ToolbarController;
@@ -74,7 +72,6 @@
   std::unique_ptr<BrowserWindowCocoa> windowShim_;
   base::scoped_nsobject<ToolbarController> toolbarController_;
   base::scoped_nsobject<TabStripControllerCocoa> tabStripController_;
-  base::scoped_nsobject<DevToolsController> devToolsController_;
   base::scoped_nsobject<OverlayableContentsController>
       overlayableContentsController_;
   base::scoped_nsobject<FullscreenToolbarControllerCocoa>
@@ -84,12 +81,6 @@
       fullscreenTransition_;
   base::scoped_nsobject<BrowserWindowTouchBarController> touchBarController_;
 
-  // Strong. StatusBubble is a special case of a strong reference that
-  // we don't wrap in a scoped_ptr because it is acting the same
-  // as an NSWindowController in that it wraps a window that must
-  // be shut down before our destructors are called.
-  StatusBubbleMac* statusBubble_;
-
   BOOL initializing_;  // YES while we are currently in initWithBrowser:
   BOOL ownsBrowser_;  // Only ever NO when testing
 
@@ -203,9 +194,6 @@
 // Return a weak pointer to the tab strip controller.
 - (TabStripControllerCocoa*)tabStripController;
 
-// Access the C++ bridge object representing the status bubble for the window.
-- (StatusBubbleMac*)statusBubble;
-
 // Access the C++ bridge object representing the location bar.
 - (LocationBarViewMac*)locationBarBridge;
 
@@ -273,8 +261,6 @@
 // Returns YES if the bookmark bar is currently animating.
 - (BOOL)isBookmarkBarAnimating;
 
-- (DevToolsController*)devToolsController;
-
 // The user changed the theme.
 - (void)userChangedTheme;
 
@@ -284,9 +270,6 @@
 - (BOOL)handledByExtensionCommand:(NSEvent*)event
     priority:(ui::AcceleratorManager::HandlerPriority)priority;
 
-// Delegate method for the status bubble to query its base frame.
-- (NSRect)statusBubbleBaseFrame;
-
 // Dismiss the permission bubble
 - (void)dismissPermissionBubble;
 
@@ -353,11 +336,6 @@
 // otherwise). (E.g., normal browser windows do, pop-ups do not.)
 - (BOOL)hasToolbar;
 
-// Called to check whether or not this window has a location bar (YES if it
-// does, NO otherwise). (E.g., normal browser windows do, pop-ups may or may
-// not.)
-- (BOOL)hasLocationBar;
-
 // Called to check whether or not this window can have bookmark bar (YES if it
 // does, NO otherwise). (E.g., normal browser windows may, pop-ups may not.)
 - (BOOL)supportsBookmarkBar;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index bae55c6a..679f690e 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -47,7 +47,6 @@
 #import "chrome/browser/ui/cocoa/browser_window_controller_private.h"
 #import "chrome/browser/ui/cocoa/browser_window_layout.h"
 #import "chrome/browser/ui/cocoa/browser_window_utils.h"
-#import "chrome/browser/ui/cocoa/dev_tools_controller.h"
 #include "chrome/browser/ui/cocoa/extensions/extension_keybinding_registry_cocoa.h"
 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
@@ -56,9 +55,6 @@
 #include "chrome/browser/ui/cocoa/fullscreen_placeholder_view.h"
 #import "chrome/browser/ui/cocoa/fullscreen_window.h"
 #include "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#import "chrome/browser/ui/cocoa/status_bubble_mac.h"
 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h"
@@ -289,20 +285,11 @@
     // of the toolbar/tabstrip is known.
     windowShim_->SetBounds(windowRect);
 
-    // Create a sub-controller for the docked devTools and add its view to the
-    // hierarchy.
-    devToolsController_.reset([[DevToolsController alloc] init]);
-    [[devToolsController_ view] setFrame:[[self tabContentArea] bounds]];
-    [[self tabContentArea] addSubview:[devToolsController_ view]];
-
     // Create the overlayable contents controller.  This provides the switch
     // view that TabStripControllerCocoa needs.
     overlayableContentsController_.reset(
         [[OverlayableContentsController alloc] init]);
-    [[overlayableContentsController_ view]
-        setFrame:[[devToolsController_ view] bounds]];
-    [[devToolsController_ view]
-        addSubview:[overlayableContentsController_ view]];
+    [[self tabContentArea] addSubview:[overlayableContentsController_ view]];
 
     // Create a controller for the tab strip, giving it the model object for
     // this window's Browser and the tab strip view. The controller will handle
@@ -319,8 +306,7 @@
                  profile:browser->profile()
                  browser:browser]);
     [[toolbarController_ toolbarView] setResizeDelegate:self];
-    [toolbarController_ setHasToolbar:[self hasToolbar]
-                       hasLocationBar:[self hasLocationBar]];
+    [toolbarController_ setHasToolbar:[self hasToolbar] hasLocationBar:NO];
 
     [self updateFullscreenCollectionBehavior];
 
@@ -347,9 +333,6 @@
       }
     }
 
-    // Create the bridge for the status bubble.
-    statusBubble_ = new StatusBubbleMac([self window], self);
-
     extensionKeybindingRegistry_.reset(
         new ExtensionKeybindingRegistryCocoa(browser_->profile(),
             [self window],
@@ -445,10 +428,6 @@
   return tabStripController_.get();
 }
 
-- (StatusBubbleMac*)statusBubble {
-  return statusBubble_;
-}
-
 - (LocationBarViewMac*)locationBarBridge {
   return [toolbarController_ locationBarBridge];
 }
@@ -495,11 +474,6 @@
   DCHECK(browser_->tab_strip_model()->empty());
   [savedRegularWindow_ close];
 
-  // We delete statusBubble here because we need to kill off the dependency
-  // that its window has on our window before our window goes away.
-  delete statusBubble_;
-  statusBubble_ = NULL;
-
   // We can't actually use |-autorelease| here because there's an embedded
   // run loop in the |-performClose:| which contains its own autorelease pool.
   // Instead call it after a zero-length delay, which gets us back to the main
@@ -510,8 +484,6 @@
 }
 
 - (void)updateDevToolsForContents:(WebContents*)contents {
-  [devToolsController_ updateDevToolsForWebContents:contents
-                                        withProfile:browser_->profile()];
 }
 
 // Called when the user wants to close a window or from the shutdown process.
@@ -905,13 +877,6 @@
       content::NativeWebKeyboardEvent(event), priority);
 }
 
-// StatusBubble delegate method: tell the status bubble the frame it should
-// position itself in.
-- (NSRect)statusBubbleBaseFrame {
-  NSView* view = [overlayableContentsController_ view];
-  return [view convertRect:[view bounds] toView:nil];
-}
-
 - (void)updateToolbarWithContents:(WebContents*)tab {
   [toolbarController_ updateToolbarWithContents:tab];
 }
@@ -1082,7 +1047,6 @@
 
 // Make the location bar the first responder, if possible.
 - (void)focusLocationBar:(BOOL)selectAll {
-  [toolbarController_ focusLocationBar:selectAll];
 }
 
 - (void)focusTabContents {
@@ -1241,10 +1205,6 @@
   return NO;
 }
 
-- (DevToolsController*)devToolsController {
-  return devToolsController_;
-}
-
 - (NSWindow*)createFullscreenWindow {
   NSWindow* window = [[[FullscreenWindow alloc]
       initForScreen:[[self window] screen]] autorelease];
@@ -1301,8 +1261,6 @@
 
   // Update all the UI bits.
   windowShim_->UpdateTitleBar();
-  [devToolsController_ updateDevToolsForWebContents:contents
-                                        withProfile:browser_->profile()];
 }
 
 - (void)onTabChanged:(TabChangeType)change withContents:(WebContents*)contents {
@@ -1404,13 +1362,6 @@
 // Delegate method called when window is resized.
 - (void)windowDidResize:(NSNotification*)notification {
   [self saveWindowPositionIfNeeded];
-
-  // Resize (and possibly move) the status bubble. Note that we may get called
-  // when the status bubble does not exist.
-  if (statusBubble_) {
-    statusBubble_->UpdateSizeAndPosition();
-  }
-
   [self updatePermissionBubbleAnchor];
 }
 
@@ -1676,8 +1627,7 @@
 }
 
 - (BOOL)floatingBarHasFocus {
-  NSResponder* focused = [[self window] firstResponder];
-  return [focused isKindOfClass:[AutocompleteTextFieldEditor class]];
+  return NO;
 }
 
 - (BOOL)isFullscreenForTabContentOrExtension {
@@ -1712,10 +1662,6 @@
          [self supportsWindowFeature:Browser::FEATURE_TOOLBAR];
 }
 
-- (BOOL)hasLocationBar {
-  return [self supportsWindowFeature:Browser::FEATURE_LOCATIONBAR];
-}
-
 - (BOOL)supportsBookmarkBar {
   return NO;
 }
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
index a0b5d38..52bc156 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_browsertest.mm
@@ -32,7 +32,6 @@
 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
 #import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h"
 #import "chrome/browser/ui/cocoa/history_overlay_controller.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
@@ -548,7 +547,6 @@
 
   // Insert a non-NTP new tab in the foreground.
   AddTabAtIndex(0, GURL("http://google.com"), ui::PAGE_TRANSITION_LINK);
-  ASSERT_FALSE([[controller() toolbarController] isLocationBarFocused]);
   EXPECT_TRUE([fullscreenToolbarController isRevealingToolbar]);
   [fullscreenToolbarController resetToolbarFlag];
 
@@ -559,19 +557,16 @@
 
   // Insert a NTP new tab in the foreground.
   AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_LINK);
-  ASSERT_TRUE([[controller() toolbarController] isLocationBarFocused]);
   EXPECT_TRUE([fullscreenToolbarController isRevealingToolbar]);
   [fullscreenToolbarController resetToolbarFlag];
 
   AddTabAtBackground(1, GURL("http://google.com"));
-  ASSERT_TRUE([[controller() toolbarController] isLocationBarFocused]);
   EXPECT_TRUE([fullscreenToolbarController isRevealingToolbar]);
   [fullscreenToolbarController resetToolbarFlag];
 
   // Switch to a non-NTP tab.
   TabStripModel* model = browser()->tab_strip_model();
   model->ActivateTabAt(1, true);
-  ASSERT_FALSE([[controller() toolbarController] isLocationBarFocused]);
   EXPECT_TRUE([fullscreenToolbarController isRevealingToolbar]);
   [fullscreenToolbarController resetToolbarFlag];
 }
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index 17b26c7..bdf54b92 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -25,15 +25,12 @@
 #import "chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h"
 #import "chrome/browser/ui/cocoa/browser_window_layout.h"
 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
-#import "chrome/browser/ui/cocoa/dev_tools_controller.h"
 #import "chrome/browser/ui/cocoa/fast_resize_view.h"
 #import "chrome/browser/ui/cocoa/floating_bar_backing_view.h"
 #import "chrome/browser/ui/cocoa/framed_browser_window.h"
 #import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller_cocoa.h"
 #import "chrome/browser/ui/cocoa/fullscreen_window.h"
 #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
-#include "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
-#import "chrome/browser/ui/cocoa/status_bubble_mac.h"
 #import "chrome/browser/ui/cocoa/tab_contents/overlayable_contents_controller.h"
 #import "chrome/browser/ui/cocoa/tab_contents/tab_contents_controller.h"
 #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h"
@@ -345,10 +342,6 @@
   [self setWindow:destWindow];
   [destWindow setWindowController:[self nsWindowController]];
 
-  // Move the status bubble over, if we have one.
-  if (statusBubble_)
-    statusBubble_->SwitchParentWindow(destWindow);
-
   [self updatePermissionBubbleAnchor];
 
   // Move the title over.
@@ -723,7 +716,7 @@
   [fullscreenToolbarController_ enterFullscreenMode];
 
   if (!floatingBarBackingView_.get() &&
-      ([self hasTabStrip] || [self hasToolbar] || [self hasLocationBar])) {
+      ([self hasTabStrip] || [self hasToolbar])) {
     floatingBarBackingView_.reset(
         [[FloatingBarBackingView alloc] initWithFrame:NSZeroRect]);
     [floatingBarBackingView_
@@ -832,8 +825,6 @@
 
   [layout setHasToolbar:[self hasToolbar]];
   [layout setToolbarHeight:NSHeight([[toolbarController_ view] bounds])];
-
-  [layout setHasLocationBar:[self hasLocationBar]];
 }
 
 - (void)applyLayout:(BrowserWindowLayout*)layout {
@@ -898,21 +889,6 @@
     return;
   }
 
-  // Removing the location bar from the window causes it to resign first
-  // responder. Remember the location bar's focus state in order to restore
-  // it before returning.
-  BOOL locationBarHadFocus = [toolbarController_ locationBarHasFocus];
-  FullscreenToolbarVisibilityLockController* visibilityLockController = nil;
-  if (locationBarHadFocus) {
-    // The location bar, by being focused, has a visibility lock on the toolbar,
-    // and the location bar's removal from the view hierarchy will allow the
-    // toolbar to hide. Create a temporary visibility lock on the toolbar for
-    // the duration of the view hierarchy change.
-    visibilityLockController = [self fullscreenToolbarVisibilityLockController];
-    [visibilityLockController lockToolbarVisibilityForOwner:self
-                                              withAnimation:NO];
-  }
-
   // Remove all subviews that aren't the tabContentArea.
   for (NSView* view in [[[self.chromeContentView subviews] copy] autorelease]) {
     if (view != tabContentArea)
@@ -935,14 +911,6 @@
                             positioned:NSWindowAbove
                             relativeTo:nil];
   }
-
-  // Restore the location bar's focus state and remove the temporary visibility
-  // lock.
-  if (locationBarHadFocus) {
-    [self focusLocationBar:YES];
-    [visibilityLockController releaseToolbarVisibilityForOwner:self
-                                                 withAnimation:NO];
-  }
 }
 
 - (BOOL)shouldUseCustomAppKitFullscreenTransition:(BOOL)enterFullScreen {
diff --git a/chrome/browser/ui/cocoa/bubble_anchor_helper.mm b/chrome/browser/ui/cocoa/bubble_anchor_helper.mm
index 66be9831..e432ce4 100644
--- a/chrome/browser/ui/cocoa/bubble_anchor_helper.mm
+++ b/chrome/browser/ui/cocoa/bubble_anchor_helper.mm
@@ -13,7 +13,6 @@
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
 #import "chrome/browser/ui/cocoa/fullscreen/fullscreen_toolbar_controller.h"
 #import "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 #import "ui/base/cocoa/cocoa_base_utils.h"
 
 bool HasVisibleLocationBarForBrowser(Browser* browser) {
diff --git a/chrome/browser/ui/cocoa/bubble_combobox.h b/chrome/browser/ui/cocoa/bubble_combobox.h
deleted file mode 100644
index d7ee71e7..0000000
--- a/chrome/browser/ui/cocoa/bubble_combobox.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_BUBBLE_COMBOBOX_H_
-#define CHROME_BROWSER_UI_COCOA_BUBBLE_COMBOBOX_H_
-
-#import <Cocoa/Cocoa.h>
-
-namespace ui {
-class ComboboxModel;
-}  // namespace ui
-
-// An NSPopUpButton that auto-populates from a ui::ComboboxModel.
-// By default it comes with a border, small font size, and small control size.
-@interface BubbleCombobox : NSPopUpButton
-// Does not take ownership nor store a pointer to |model|; it is used only for
-// population of the combobox.
-- (id)initWithFrame:(NSRect)frame
-          pullsDown:(BOOL)pullsDown
-              model:(ui::ComboboxModel*)model;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_BUBBLE_COMBOBOX_H_
diff --git a/chrome/browser/ui/cocoa/bubble_combobox.mm b/chrome/browser/ui/cocoa/bubble_combobox.mm
deleted file mode 100644
index b093fcc..0000000
--- a/chrome/browser/ui/cocoa/bubble_combobox.mm
+++ /dev/null
@@ -1,32 +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.
-
-#import "chrome/browser/ui/cocoa/bubble_combobox.h"
-
-#include "base/strings/sys_string_conversions.h"
-#include "ui/base/models/combobox_model.h"
-
-@implementation BubbleCombobox
-
-- (id)initWithFrame:(NSRect)frame
-          pullsDown:(BOOL)pullsDown
-              model:(ui::ComboboxModel*)model {
-  if ((self = [super initWithFrame:frame pullsDown:pullsDown])) {
-    [self setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
-    [self setBordered:YES];
-    [[self cell] setControlSize:NSSmallControlSize];
-
-    for (int i = 0; i < model->GetItemCount(); ++i) {
-      if (model->IsItemSeparatorAt(i))
-        [[self menu] addItem:[NSMenuItem separatorItem]];
-      else
-        [self addItemWithTitle:base::SysUTF16ToNSString(model->GetItemAt(i))];
-    }
-
-    [self selectItemAtIndex:model->GetDefaultIndex()];
-  }
-  return self;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/bubble_view.h b/chrome/browser/ui/cocoa/bubble_view.h
deleted file mode 100644
index feeece3..0000000
--- a/chrome/browser/ui/cocoa/bubble_view.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_BUBBLE_VIEW_H_
-#define CHROME_BROWSER_UI_COCOA_BUBBLE_VIEW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-
-// A view class that looks like a "bubble" with rounded corners and displays
-// text inside. Can be themed. To put flush against the sides of a window, the
-// corner flags can be adjusted.
-
-// Constants that define where the bubble will have a rounded corner. If
-// not set, the corner will be square.
-enum {
-  kRoundedTopLeftCorner = 1,
-  kRoundedTopRightCorner = 1 << 1,
-  kRoundedBottomLeftCorner = 1 << 2,
-  kRoundedBottomRightCorner = 1 << 3,
-  kRoundedAllCorners = kRoundedTopLeftCorner |
-                       kRoundedTopRightCorner |
-                       kRoundedBottomLeftCorner |
-                       kRoundedBottomRightCorner
-};
-
-// Constants that affect where the text is positioned within the view. They
-// are exposed in case anyone needs to use the padding to set the content string
-// length appropriately based on available space (such as eliding a URL).
-enum {
-  kBubbleViewTextPositionX = 4,
-  kBubbleViewTextPositionY = 2
-};
-
-@interface BubbleView : NSView {
- @private
-  base::scoped_nsobject<NSString> content_;
-  unsigned long cornerFlags_;
-  // The window from which we get the theme used to draw. In some cases,
-  // it might not be the window we're in. As a result, this may or may not
-  // directly own us, so it needs to be weak to prevent a cycle.
-  NSWindow* themeProvider_;
-}
-
-// Sets the string displayed in the bubble. A copy of the string is made.
-- (void)setContent:(NSString*)content;
-
-// Sets which corners will be rounded.
-- (void)setCornerFlags:(unsigned long)flags;
-
-// Sets the window whose theme is used to draw.
-- (void)setThemeProvider:(NSWindow*)provider;
-
-// The font used to display the content string.
-- (NSFont*)font;
-
-@end
-
-// APIs exposed only for testing.
-@interface BubbleView(TestingOnly)
-- (NSString*)content;
-- (unsigned long)cornerFlags;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_BUBBLE_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/bubble_view.mm b/chrome/browser/ui/cocoa/bubble_view.mm
deleted file mode 100644
index 6eb0ec5..0000000
--- a/chrome/browser/ui/cocoa/bubble_view.mm
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/bubble_view.h"
-
-#include "chrome/browser/themes/theme_properties.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSBezierPath+RoundRect.h"
-#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSColor+Luminance.h"
-#include "ui/base/theme_provider.h"
-
-// The roundedness of the edges of the bubble. This matches the value used on
-// Lion for window corners.
-const int kBubbleCornerRadius = 3;
-const float kWindowEdge = 0.7f;
-
-@implementation BubbleView
-
-- (id)initWithFrame:(NSRect)frame {
-  if ((self = [super initWithFrame:frame])) {
-    cornerFlags_ = kRoundedAllCorners;
-  }
-  return self;
-}
-
-// Sets the string displayed in the bubble. A copy of the string is made.
-- (void)setContent:(NSString*)content {
-  if ([content_ isEqualToString:content])
-    return;
-  content_.reset([content copy]);
-  [self setNeedsDisplay:YES];
-}
-
-// Sets which corners will be rounded.
-- (void)setCornerFlags:(unsigned long)flags {
-  if (cornerFlags_ == flags)
-    return;
-  cornerFlags_ = flags;
-  [self setNeedsDisplay:YES];
-}
-
-- (void)setThemeProvider:(NSWindow*)provider {
-  if (themeProvider_ == provider)
-    return;
-  themeProvider_ = provider;
-  [self setNeedsDisplay:YES];
-}
-
-- (NSString*)content {
-  return content_.get();
-}
-
-- (unsigned long)cornerFlags {
-  return cornerFlags_;
-}
-
-// The font used to display the content string.
-- (NSFont*)font {
-  return [NSFont systemFontOfSize:[NSFont smallSystemFontSize]];
-}
-
-// Draws the themed background and the text. Will draw a gray bg if no theme.
-- (void)drawRect:(NSRect)rect {
-  float topLeftRadius =
-      cornerFlags_ & kRoundedTopLeftCorner ? kBubbleCornerRadius : 0;
-  float topRightRadius =
-      cornerFlags_ & kRoundedTopRightCorner ? kBubbleCornerRadius : 0;
-  float bottomLeftRadius =
-      cornerFlags_ & kRoundedBottomLeftCorner ? kBubbleCornerRadius : 0;
-  float bottomRightRadius =
-      cornerFlags_ & kRoundedBottomRightCorner ? kBubbleCornerRadius : 0;
-
-  const ui::ThemeProvider* themeProvider = themeProvider_
-                                               ? [themeProvider_ themeProvider]
-                                               : [[self window] themeProvider];
-
-  // Background / Edge
-
-  NSRect bounds = [self bounds];
-  bounds = NSInsetRect(bounds, 0.5, 0.5);
-  NSBezierPath* border =
-      [NSBezierPath gtm_bezierPathWithRoundRect:bounds
-                            topLeftCornerRadius:topLeftRadius
-                           topRightCornerRadius:topRightRadius
-                         bottomLeftCornerRadius:bottomLeftRadius
-                        bottomRightCornerRadius:bottomRightRadius];
-
-  if (themeProvider)
-    [themeProvider->GetNSColor(ThemeProperties::COLOR_TOOLBAR) set];
-  [border fill];
-
-  [[NSColor colorWithDeviceWhite:kWindowEdge alpha:1.0f] set];
-  [border stroke];
-
-  // Text
-  NSColor* textColor = [NSColor blackColor];
-  if (themeProvider)
-    textColor = themeProvider->GetNSColor(ThemeProperties::COLOR_TAB_TEXT);
-  NSFont* textFont = [self font];
-  base::scoped_nsobject<NSShadow> textShadow([[NSShadow alloc] init]);
-  [textShadow setShadowBlurRadius:0.0f];
-  [textShadow.get() setShadowColor:[textColor gtm_legibleTextColor]];
-  [textShadow.get() setShadowOffset:NSMakeSize(0.0f, -1.0f)];
-
-  NSDictionary* textDict = [NSDictionary dictionaryWithObjectsAndKeys:
-      textColor, NSForegroundColorAttributeName,
-      textFont, NSFontAttributeName,
-      textShadow.get(), NSShadowAttributeName,
-      nil];
-  [content_ drawAtPoint:NSMakePoint(kBubbleViewTextPositionX,
-                                    kBubbleViewTextPositionY)
-         withAttributes:textDict];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/bubble_view_unittest.mm b/chrome/browser/ui/cocoa/bubble_view_unittest.mm
deleted file mode 100644
index 7749950..0000000
--- a/chrome/browser/ui/cocoa/bubble_view_unittest.mm
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/bubble_view.h"
-#include "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#import "testing/gtest_mac.h"
-
-class BubbleViewTest : public CocoaTest {
- public:
-  BubbleViewTest() {
-    NSRect frame = NSMakeRect(0, 0, 50, 50);
-    base::scoped_nsobject<BubbleView> view(
-        [[BubbleView alloc] initWithFrame:frame]);
-    [view setThemeProvider:test_window()];
-    view_ = view.get();
-    [[test_window() contentView] addSubview:view_];
-    [view_ setContent:@"Hi there, I'm a bubble view"];
-  }
-
-  BubbleView* view_;
-};
-
-TEST_VIEW(BubbleViewTest, view_);
-
-// Test with no themeProvider.
-TEST_F(BubbleViewTest, NilThemeProvider) {
-  NSRect frame = NSMakeRect(0, 0, 50, 50);
-  base::scoped_nsobject<BubbleView> view(
-      [[BubbleView alloc] initWithFrame:frame]);
-  [[test_window() contentView] addSubview:view.get()];
-  [view display];
-}
-
-// Make sure things don't go haywire when given invalid or long strings.
-TEST_F(BubbleViewTest, SetContent) {
-  [view_ setContent:nil];
-  EXPECT_TRUE([view_ content] == nil);
-  [view_ setContent:@""];
-  EXPECT_NSEQ(@"", [view_ content]);
-  NSString* str = @"This is a really really long string that's just too long";
-  [view_ setContent:str];
-  EXPECT_NSEQ(str, [view_ content]);
-}
-
-TEST_F(BubbleViewTest, CornerFlags) {
-  // Set some random flags just to check.
-  [view_ setCornerFlags:kRoundedTopRightCorner | kRoundedTopLeftCorner];
-  EXPECT_EQ([view_ cornerFlags],
-            (unsigned long)kRoundedTopRightCorner | kRoundedTopLeftCorner);
-  // Set no flags (all 4 draw corners are square).
-  [view_ setCornerFlags:0];
-  EXPECT_EQ([view_ cornerFlags], 0UL);
-  // Set all bits. Meaningless past the first 4, but harmless to set too many.
-  [view_ setCornerFlags:0xFFFFFFFF];
-  EXPECT_EQ([view_ cornerFlags], 0xFFFFFFFF);
-}
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller.h b/chrome/browser/ui/cocoa/dev_tools_controller.h
deleted file mode 100644
index b27b70b..0000000
--- a/chrome/browser/ui/cocoa/dev_tools_controller.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_
-#define CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "chrome/browser/devtools/devtools_window.h"
-
-@class FocusTracker;
-@class DevToolsContainerView;
-class Profile;
-
-namespace content {
-class WebContents;
-}
-
-// A class that handles updates of the devTools view within a browser window.
-// It swaps in the relevant devTools contents for a given WebContents or removes
-// the view, if there's no devTools contents to show.
-@interface DevToolsController : NSObject {
- @private
-  // A view hosting docked devTools contents.
-  base::scoped_nsobject<DevToolsContainerView> devToolsContainerView_;
-
-  base::scoped_nsobject<FocusTracker> focusTracker_;
-}
-
-- (id)init;
-
-// This controller's view.
-- (NSView*)view;
-
-// Depending on |contents|'s state, decides whether the docked web inspector
-// should be shown or hidden and adjusts inspected page position.
-// Returns true iff layout has changed.
-- (BOOL)updateDevToolsForWebContents:(content::WebContents*)contents
-                         withProfile:(Profile*)profile;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_DEV_TOOLS_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller.mm b/chrome/browser/ui/cocoa/dev_tools_controller.mm
deleted file mode 100644
index 43180271..0000000
--- a/chrome/browser/ui/cocoa/dev_tools_controller.mm
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/dev_tools_controller.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include <Cocoa/Cocoa.h>
-
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/profiles/profile.h"
-#import "chrome/browser/ui/cocoa/view_id_util.h"
-#include "components/prefs/pref_service.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/cocoa/base_view.h"
-#include "ui/base/cocoa/focus_tracker.h"
-#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/mac/scoped_cocoa_disable_screen_updates.h"
-
-using content::WebContents;
-
-@interface DevToolsContainerView : BaseView {
-  DevToolsContentsResizingStrategy strategy_;
-
-  // Weak references. Ownership via -subviews.
-  NSView* devToolsView_;
-  NSView* contentsView_;
-}
-
-// Returns true iff layout has changed.
-- (BOOL)setDevToolsView:(NSView*)devToolsView
-           withStrategy:(const DevToolsContentsResizingStrategy&)strategy;
-- (void)adjustSubviews;
-- (BOOL)hasDevToolsView;
-
-@end
-
-
-@implementation DevToolsContainerView
-
-- (BOOL)setDevToolsView:(NSView*)devToolsView
-           withStrategy:(const DevToolsContentsResizingStrategy&)strategy {
-  BOOL strategy_changed = !strategy_.Equals(strategy);
-  strategy_.CopyFrom(strategy);
-  if (devToolsView == devToolsView_) {
-    if (contentsView_)
-      [contentsView_ setHidden:strategy.hide_inspected_contents()];
-    return strategy_changed;
-  }
-
-  if (devToolsView_) {
-    DCHECK_EQ(2u, [[self subviews] count]);
-    [devToolsView_ removeFromSuperview];
-    [contentsView_ setHidden:NO];
-    contentsView_ = nil;
-    devToolsView_ = nil;
-  }
-
-  if (devToolsView) {
-    NSArray* subviews = [self subviews];
-    DCHECK_EQ(1u, [subviews count]);
-    contentsView_ = [subviews objectAtIndex:0];
-    devToolsView_ = devToolsView;
-    // Place DevTools under contents.
-    [self addSubview:devToolsView positioned:NSWindowBelow relativeTo:nil];
-
-    [contentsView_ setHidden:strategy.hide_inspected_contents()];
-  }
-
-  return YES;
-}
-
-- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
-  [self adjustSubviews];
-}
-
-- (BOOL)hasDevToolsView {
-  return devToolsView_ != nil;
-}
-
-- (void)adjustSubviews {
-  if (![[self subviews] count])
-    return;
-
-  if (!devToolsView_) {
-    DCHECK_EQ(1u, [[self subviews] count]);
-    NSView* contents = [[self subviews] objectAtIndex:0];
-    [contents setFrame:[self bounds]];
-    return;
-  }
-
-  DCHECK_EQ(2u, [[self subviews] count]);
-
-  gfx::Rect new_devtools_bounds;
-  gfx::Rect new_contents_bounds;
-  ApplyDevToolsContentsResizingStrategy(
-      strategy_, gfx::Size(NSSizeToCGSize([self bounds].size)),
-      &new_devtools_bounds, &new_contents_bounds);
-  [devToolsView_ setFrame:[self flipRectToNSRect:new_devtools_bounds]];
-  [contentsView_ setFrame:[self flipRectToNSRect:new_contents_bounds]];
-}
-
-@end
-
-
-@implementation DevToolsController
-
-- (id)init {
-  if ((self = [super init])) {
-    devToolsContainerView_.reset(
-        [[DevToolsContainerView alloc] initWithFrame:NSZeroRect]);
-    [devToolsContainerView_
-        setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
-  }
-  return self;
-}
-
-- (NSView*)view {
-  return devToolsContainerView_.get();
-}
-
-- (BOOL)updateDevToolsForWebContents:(WebContents*)contents
-                         withProfile:(Profile*)profile {
-  DevToolsContentsResizingStrategy strategy;
-  WebContents* devTools = DevToolsWindow::GetInTabWebContents(
-      contents, &strategy);
-
-  // Make sure we do not draw any transient arrangements of views.
-  gfx::ScopedCocoaDisableScreenUpdates disabler;
-
-  if (devTools && ![devToolsContainerView_ hasDevToolsView]) {
-    focusTracker_.reset(
-        [[FocusTracker alloc] initWithWindow:[devToolsContainerView_ window]]);
-  }
-
-  if (!devTools && [devToolsContainerView_ hasDevToolsView]) {
-    [focusTracker_ restoreFocusInWindow:[devToolsContainerView_ window]];
-    focusTracker_.reset();
-  }
-
-  NSView* devToolsView = nil;
-  if (devTools) {
-    devToolsView = devTools->GetNativeView();
-    // |devToolsView| is a WebContentsViewCocoa object, whose ViewID was
-    // set to VIEW_ID_TAB_CONTAINER initially, so we need to change it to
-    // VIEW_ID_DEV_TOOLS_DOCKED here.
-    view_id_util::SetID(devToolsView, VIEW_ID_DEV_TOOLS_DOCKED);
-
-    devTools->SetAllowOtherViews(true);
-    contents->SetAllowOtherViews(true);
-  } else {
-    contents->SetAllowOtherViews(false);
-  }
-
-  BOOL result = [devToolsContainerView_ setDevToolsView:devToolsView
-                                           withStrategy:strategy];
-  [devToolsContainerView_ adjustSubviews];
-  return result;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm b/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm
deleted file mode 100644
index bbc6ad51..0000000
--- a/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/dev_tools_controller.h"
-
-#include "base/macros.h"
-#include "chrome/browser/devtools/devtools_window.h"
-#include "chrome/browser/devtools/devtools_window_testing.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_list.h"
-#include "chrome/browser/ui/browser_window.h"
-#include "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/find_bar/find_bar.h"
-#include "chrome/browser/ui/find_bar/find_bar_controller.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/views/scoped_macviews_browser_mode.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/test/test_utils.h"
-
-class DevToolsControllerTest : public InProcessBrowserTest {
- public:
-  DevToolsControllerTest() : InProcessBrowserTest(), devtools_window_(NULL) {}
-
- protected:
-  void OpenDevToolsWindow() {
-    devtools_window_ =
-        DevToolsWindowTesting::OpenDevToolsWindowSync(browser(), true);
-  }
-
-  void CloseDevToolsWindow() {
-    DevToolsWindowTesting::CloseDevToolsWindowSync(devtools_window_);
-  }
-
-  content::WebContents* web_contents() {
-    return browser()->tab_strip_model()->GetActiveWebContents();
-  }
-
-  content::WebContents* devtools_web_contents() {
-    return DevToolsWindow::GetInTabWebContents(web_contents(), NULL);
-  }
-
-  DevToolsWindow* devtools_window_;
-
- private:
-  test::ScopedMacViewsBrowserMode cocoa_browser_mode_{false};
-
-  DISALLOW_COPY_AND_ASSIGN(DevToolsControllerTest);
-};
-
-// Verify that AllowOtherViews is set when and only when DevTools is visible.
-IN_PROC_BROWSER_TEST_F(DevToolsControllerTest, AllowOtherViews) {
-  EXPECT_FALSE(web_contents()->GetAllowOtherViews());
-
-  OpenDevToolsWindow();
-  EXPECT_TRUE(devtools_web_contents()->GetAllowOtherViews());
-  EXPECT_TRUE(web_contents()->GetAllowOtherViews());
-
-  CloseDevToolsWindow();
-  EXPECT_FALSE(web_contents()->GetAllowOtherViews());
-}
diff --git a/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm b/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
deleted file mode 100644
index 65c0670..0000000
--- a/chrome/browser/ui/cocoa/download/download_started_animation_mac.mm
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// This file contains the Mac implementation the download animation, displayed
-// at the start of a download. The animation produces an arrow pointing
-// downwards and animates towards the bottom of the window where the new
-// download appears in the download shelf.
-
-#include "chrome/browser/download/download_started_animation.h"
-
-#import <QuartzCore/QuartzCore.h>
-
-#include "base/logging.h"
-#include "chrome/app/vector_icons/vector_icons.h"
-#import "chrome/browser/ui/cocoa/animatable_image.h"
-#import "chrome/browser/ui/cocoa/md_util.h"
-#import "chrome/browser/ui/cocoa/nsview_additions.h"
-#include "chrome/common/chrome_features.h"
-#include "chrome/grit/theme_resources.h"
-#include "content/public/browser/web_contents.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/base/ui_features.h"
-#include "ui/gfx/color_palette.h"
-#import "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/gfx/paint_vector_icon.h"
-
-namespace {
-constexpr CGFloat kLeftMargin = 10;
-constexpr CGFloat kMDDownloadStartedImageSize = 72;
-}  // namespace
-
-class DownloadAnimationWebObserver;
-
-// A class for managing the Core Animation download animation.
-// Should be instantiated using +startAnimationWithWebContents:.
-@interface DownloadStartedAnimationMac : NSObject {
- @private
-  CGFloat imageWidth_;
-  AnimatableImage* animation_;
-};
-
-+ (void)startAnimationWithWebContents:(content::WebContents*)webContents;
-
-@end
-
-@implementation DownloadStartedAnimationMac
-
-- (id)initWithWebContents:(content::WebContents*)webContents {
-  if ((self = [super init])) {
-    // Load the image of the download arrow.
-    ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
-    NSImage* image =
-        base::FeatureList::IsEnabled(features::kMacMaterialDesignDownloadShelf)
-            ? NSImageFromImageSkia(gfx::CreateVectorIcon(
-                  kFileDownloadShelfIcon, kMDDownloadStartedImageSize,
-                  gfx::kGoogleBlue500))
-            : bundle.GetNativeImageNamed(IDR_DOWNLOAD_ANIMATION_BEGIN)
-                  .ToNSImage();
-
-    // Figure out the positioning in the current tab. Try to position the layer
-    // against the left edge, and three times the download image's height from
-    // the bottom of the tab, assuming there is enough room. If there isn't
-    // enough, don't show the animation and let the shelf speak for itself.
-    gfx::Rect bounds = webContents->GetContainerBounds();
-    imageWidth_ = [image size].width;
-    CGFloat imageHeight = [image size].height;
-
-    // Sanity check the size in case there's no room to display the animation.
-    if (bounds.height() < imageHeight) {
-      [self release];
-      return nil;
-    }
-
-    NSView* tabContentsView = webContents->GetNativeView();
-    NSWindow* parentWindow = [tabContentsView window];
-    if (!parentWindow) {
-      // The tab is no longer frontmost.
-      [self release];
-      return nil;
-    }
-
-    NSRect frame = [tabContentsView frame];
-    CGFloat animationHeight = MIN(bounds.height(), 4 * imageHeight);
-    frame.size = NSMakeSize(imageWidth_, animationHeight);
-    if (base::FeatureList::IsEnabled(
-            features::kMacMaterialDesignDownloadShelf)) {
-      frame.origin.x += kLeftMargin;
-    }
-    frame =
-        [tabContentsView convertRect:[tabContentsView cr_localizedRect:frame]
-                              toView:nil];
-    frame = [parentWindow convertRectToScreen:frame];
-
-    // Create the animation object to assist in animating and fading.
-    animation_ = [[AnimatableImage alloc] initWithImage:image
-                                         animationFrame:frame];
-    [parentWindow addChildWindow:animation_ ordered:NSWindowAbove];
-
-    animationHeight = MIN(bounds.height(), 3 * imageHeight);
-    [animation_ setStartFrame:CGRectMake(0, animationHeight,
-                                         imageWidth_, imageHeight)];
-    [animation_ setEndFrame:CGRectMake(0, imageHeight,
-                                       imageWidth_, imageHeight)];
-    [animation_ setStartOpacity:1.0];
-    [animation_ setEndOpacity:0.4];
-    [animation_ setDuration:0.6];
-    if (base::FeatureList::IsEnabled(
-            features::kMacMaterialDesignDownloadShelf)) {
-      [animation_ setTimingFunction:CAMediaTimingFunction
-                                        .cr_materialEaseInOutTimingFunction];
-    }
-
-    // Set up to get notified about resize events on the parent window.
-    NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
-    [center addObserver:self
-               selector:@selector(parentWindowDidResize:)
-                   name:NSWindowDidResizeNotification
-                 object:parentWindow];
-    // When the animation window closes, it needs to be removed from the
-    // parent window.
-    [center addObserver:self
-               selector:@selector(windowWillClose:)
-                   name:NSWindowWillCloseNotification
-                 object:animation_];
-    // If the parent window closes, shut everything down too.
-    [center addObserver:self
-               selector:@selector(windowWillClose:)
-                   name:NSWindowWillCloseNotification
-                 object:parentWindow];
-  }
-  return self;
-}
-
-- (void)dealloc {
-  [[NSNotificationCenter defaultCenter] removeObserver:self];
-  [super dealloc];
-}
-
-// Called when the parent window is resized.
-- (void)parentWindowDidResize:(NSNotification*)notification {
-  NSWindow* parentWindow = [animation_ parentWindow];
-  DCHECK([[notification object] isEqual:parentWindow]);
-  NSRect parentFrame = [parentWindow frame];
-  NSRect frame = parentFrame;
-  frame.size.width = MIN(imageWidth_, NSWidth(parentFrame));
-  [animation_ setFrame:frame display:YES];
-}
-
-// When the animation closes, release self.
-- (void)windowWillClose:(NSNotification*)notification {
-  [[animation_ parentWindow] removeChildWindow:animation_];
-  [self release];
-}
-
-+ (void)startAnimationWithWebContents:(content::WebContents*)contents {
-  // Will be deleted when the animation window closes.
-  DownloadStartedAnimationMac* controller =
-      [[self alloc] initWithWebContents:contents];
-  // The initializer can return nil.
-  if (!controller)
-    return;
-
-  // The |controller| releases itself when done.
-  [controller->animation_ startAnimation];
-}
-
-@end
-
-void DownloadStartedAnimation::ShowCocoa(content::WebContents* web_contents) {
-  DCHECK(web_contents);
-
-  // There's code above for an MD version of the animation, but the current
-  // plan is to not show it at all.
-  if (base::FeatureList::IsEnabled(features::kMacMaterialDesignDownloadShelf))
-    return;
-
-  // Will be deleted when the animation is complete.
-  [DownloadStartedAnimationMac startAnimationWithWebContents:web_contents];
-}
-
-#if !BUILDFLAG(MAC_VIEWS_BROWSER)
-void DownloadStartedAnimation::Show(content::WebContents* web_contents) {
-  ShowCocoa(web_contents);
-}
-#endif
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
deleted file mode 100644
index 7057e734..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/styled_text_field.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#import "chrome/browser/ui/cocoa/url_drop_target.h"
-
-@class AutocompleteTextFieldCell;
-class LocationBarDecoration;
-
-// AutocompleteTextField intercepts UI actions for forwarding to
-// OmniboxViewMac (*), and provides a custom look.  It works
-// together with AutocompleteTextFieldEditor (mostly for intercepting
-// user actions) and AutocompleteTextFieldCell (mostly for custom
-// drawing).
-//
-// For historical reasons, chrome/browser/autocomplete is the core
-// implementation of the Omnibox.  Chrome code seems to vary between
-// autocomplete and Omnibox in describing this.
-//
-// (*) OmniboxViewMac is a view in the MVC sense for the
-// Chrome internals, though it's really more of a mish-mash of model,
-// view, and controller.
-
-// Provides a hook so that we can call directly down to
-// OmniboxViewMac rather than traversing the delegate chain.
-class AutocompleteTextFieldObserver {
- public:
-  // Called before changing the selected range of the field.
-  virtual NSRange SelectionRangeForProposedRange(NSRange proposed_range) = 0;
-
-  // Called when the control-key state changes while the field is
-  // first responder.
-  virtual void OnControlKeyChanged(bool pressed) = 0;
-
-  // Called when the user pastes into the field.
-  virtual void OnPaste() = 0;
-
-  // Return |true| if there is a selection to copy.
-  virtual bool CanCopy() = 0;
-
-  // Creates a pasteboard item from the field's current selection.
-  virtual base::scoped_nsobject<NSPasteboardItem> CreatePasteboardItem() = 0;
-
-  // Copies the pasteboard item returned from |CreatePasteboardItem()| to
-  // |pboard|.
-  virtual void CopyToPasteboard(NSPasteboard* pboard) = 0;
-
-  // Returns true if the current clipboard text supports paste and go
-  // (or paste and search).
-  virtual bool CanPasteAndGo() = 0;
-
-  // Returns the appropriate "Paste and Go" or "Paste and Search"
-  // context menu string, depending on what is currently in the
-  // clipboard.  Must not be called unless CanPasteAndGo() returns
-  // true.
-  virtual int GetPasteActionStringId() = 0;
-
-  // Called when the user initiates a "paste and go" or "paste and
-  // search" into the field.
-  virtual void OnPasteAndGo() = 0;
-
-  // Called when the field's frame changes.
-  virtual void OnFrameChanged() = 0;
-
-  // Called when the popup is no longer appropriate, such as when the
-  // field's window loses focus or a page action is clicked.
-  virtual void ClosePopup() = 0;
-
-  // Called when the user begins editing the field, for every edit,
-  // and when the user is done editing the field.
-  virtual void OnDidBeginEditing() = 0;
-  virtual void OnBeforeChange() = 0;
-  virtual void OnDidChange() = 0;
-  virtual void OnDidEndEditing() = 0;
-
-  // Called when -insertText: is invoked on the editor.
-  virtual void OnInsertText() = 0;
-
-  // Called before a -drawRect: operation.
-  virtual void OnBeforeDrawRect() = 0;
-
-  // Called after the completion of a -drawRect: operation.
-  virtual void OnDidDrawRect() = 0;
-
-  // NSResponder translates certain keyboard actions into selectors
-  // passed to -doCommandBySelector:.  The selector is forwarded here,
-  // return true if |cmd| is handled, false if the caller should
-  // handle it.
-  // TODO(shess): For now, I think having the code which makes these
-  // decisions closer to the other autocomplete code is worthwhile,
-  // since it calls a wide variety of methods which otherwise aren't
-  // clearly relevent to expose here.  But consider pulling more of
-  // the OmniboxViewMac calls up to here.
-  virtual bool OnDoCommandBySelector(SEL cmd) = 0;
-
-  // Called whenever the autocomplete text field gets focused.
-  virtual void OnSetFocus(bool control_down) = 0;
-
-  // Called whenever the autocomplete text field is losing focus.
-  virtual void OnKillFocus() = 0;
-
-  // Called before the text field handles a mouse down event.
-  virtual void OnMouseDown(NSInteger button_number) = 0;
-
- protected:
-  virtual ~AutocompleteTextFieldObserver() {}
-};
-
-@interface AutocompleteTextField : StyledTextField<NSTextViewDelegate,
-                                                   URLDropTarget,
-                                                   ThemedWindowDrawing> {
- @private
-  // Undo manager for this text field.  We use a specific instance rather than
-  // the standard undo manager in order to let us clear the undo stack at will.
-  base::scoped_nsobject<NSUndoManager> undoManager_;
-
-  AutocompleteTextFieldObserver* observer_;  // weak, owned by location bar.
-
-  // Handles being a drag-and-drop target.
-  base::scoped_nsobject<URLDropTargetHandler> dropHandler_;
-
-  // Holds current tooltip strings, to keep them from being dealloced.
-  base::scoped_nsobject<NSMutableArray> currentToolTips_;
-
-  // Animation object used for resizing the autocomplete field.
-  base::scoped_nsobject<NSViewAnimation> resizeAnimation_;
-}
-
-@property(nonatomic) AutocompleteTextFieldObserver* observer;
-
-// Convenience method to return the cell, casted appropriately.
-- (AutocompleteTextFieldCell*)cell;
-
-// Superclass aborts editing before changing the string, which causes
-// problems for undo.  This version modifies the field editor's
-// contents if the control is already being edited.
-- (void)setAttributedStringValue:(NSAttributedString*)aString;
-
-// Clears the undo chain for this text field.
-- (void)clearUndoChain;
-
-// Animates the text field to the given |frame|.
-- (void)animateToFrame:(NSRect)frame;
-
-// Stops the current animation, if any. The frame will be set to the current
-// (mid-animation) frame.
-- (void)stopAnimation;
-
-// Updates cursor and tooltip rects depending on the contents of the text field
-// e.g. the security icon should have a default pointer shown on hover instead
-// of an I-beam.
-- (void)updateMouseTracking;
-
-// Return the appropriate menu for any decoration under |event|.
-- (NSMenu*)decorationMenuForEvent:(NSEvent*)event;
-
-// Retains |tooltip| (in |currentToolTips_|) and adds this tooltip
-// via -[NSView addToolTipRect:owner:userData:].
-- (void)addToolTip:(NSString*)tooltip forRect:(NSRect)aRect;
-
-// Obtain the bubble anchor point for |decoration| in window coordinates.
-- (NSPoint)bubblePointForDecoration:(LocationBarDecoration*)decoration;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
deleted file mode 100644
index b472721..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.mm
+++ /dev/null
@@ -1,559 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-
-#include "base/logging.h"
-#import "base/mac/mac_util.h"
-#import "base/mac/sdk_forward_declarations.h"
-#include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/ui/cocoa/browser_dialogs_views_mac.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#include "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
-#import "chrome/browser/ui/cocoa/url_drop_target.h"
-#import "chrome/browser/ui/cocoa/view_id_util.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-
-namespace {
-const CGFloat kResizeAnimationDuration = 0.2;
-}
-
-@implementation AutocompleteTextField
-
-@synthesize observer = observer_;
-
-+ (Class)cellClass {
-  return [AutocompleteTextFieldCell class];
-}
-
-- (void)dealloc {
-  [[NSNotificationCenter defaultCenter] removeObserver:self];
-  [super dealloc];
-}
-
-- (void)awakeFromNib {
-  DCHECK([[self cell] isKindOfClass:[AutocompleteTextFieldCell class]]);
-  [[self cell] setTruncatesLastVisibleLine:YES];
-  [[self cell] setLineBreakMode:NSLineBreakByTruncatingTail];
-  currentToolTips_.reset([[NSMutableArray alloc] init]);
-  resizeAnimation_.reset([[NSViewAnimation alloc] init]);
-  [resizeAnimation_ setDuration:kResizeAnimationDuration];
-  [resizeAnimation_ setAnimationBlockingMode:NSAnimationNonblocking];
-  [self setAlignment:cocoa_l10n_util::ShouldDoExperimentalRTLLayout()
-                         ? NSRightTextAlignment
-                         : NSLeftTextAlignment];
-
-  // Disable Force Touch in the Omnibox. Note that this API is documented as
-  // being available in 10.11 or higher, but if the API is available in an older
-  // version we still want to use it. That prevents us from guarding the call
-  // with @available, so instead we use respondsToSelector and silence the
-  // availability warning. Also, because NSPressureConfiguration is not in the
-  // original 10.10 SDK, use NSClassFromString() to instantiate it (otherwise
-  // there's a linker error).
-  if (base::mac::IsAtLeastOS10_10() &&
-      [self respondsToSelector:@selector(setPressureConfiguration:)]) {
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability"
-    NSPressureConfiguration* pressureConfiguration =
-        [[[NSClassFromString(@"NSPressureConfiguration") alloc]
-            initWithPressureBehavior:NSPressureBehaviorPrimaryClick]
-                autorelease];
-    [self setPressureConfiguration:pressureConfiguration];
-#pragma clang diagnostic pop
-  }
-}
-
-- (void)flagsChanged:(NSEvent*)theEvent {
-  if (observer_) {
-    const bool controlFlag = ([theEvent modifierFlags]&NSControlKeyMask) != 0;
-    observer_->OnControlKeyChanged(controlFlag);
-  }
-}
-
-- (AutocompleteTextFieldCell*)cell {
-  NSCell* cell = [super cell];
-  if (!cell)
-    return nil;
-
-  DCHECK([cell isKindOfClass:[AutocompleteTextFieldCell class]]);
-  return static_cast<AutocompleteTextFieldCell*>(cell);
-}
-
-// Reroute events for the decoration area to the field editor.  This
-// will cause the cursor to be moved as close to the edge where the
-// event was seen as possible.
-//
-// The reason for this code's existence is subtle.  NSTextField
-// implements text selection and editing in terms of a "field editor".
-// This is an NSTextView which is installed as a subview of the
-// control when the field becomes first responder.  When the field
-// editor is installed, it will get -mouseDown: events and handle
-// them, rather than the text field - EXCEPT for the event which
-// caused the change in first responder, or events which fall in the
-// decorations outside the field editor's area.  In that case, the
-// default NSTextField code will setup the field editor all over
-// again, which has the side effect of doing "select all" on the text.
-// This effect can be observed with a normal NSTextField if you click
-// in the narrow border area, and is only really a problem because in
-// our case the focus ring surrounds decorations which look clickable.
-//
-// When the user first clicks on the field, after installing the field
-// editor the default NSTextField code detects if the hit is in the
-// field editor area, and if so sets the selection to {0,0} to clear
-// the selection before forwarding the event to the field editor for
-// processing (it will set the cursor position).  This also starts the
-// click-drag selection machinery.
-//
-// This code does the same thing for cases where the click was in the
-// decoration area.  This allows the user to click-drag starting from
-// a decoration area and get the expected selection behaviour,
-// likewise for multiple clicks in those areas.
-- (void)mouseDown:(NSEvent*)theEvent {
-  // TODO(groby): Figure out if OnMouseDown needs to be postponed/skipped
-  // for button decorations.
-  if (observer_)
-    observer_->OnMouseDown([theEvent buttonNumber]);
-
-  // If the click was a Control-click, bring up the context menu.
-  // |NSTextField| handles these cases inconsistently if the field is
-  // not already first responder.
-  if (([theEvent modifierFlags] & NSControlKeyMask) != 0) {
-    NSText* editor = [self currentEditor];
-    NSMenu* menu = [editor menuForEvent:theEvent];
-    [NSMenu popUpContextMenu:menu withEvent:theEvent forView:editor];
-    return;
-  }
-
-  const NSPoint location =
-      [self convertPoint:[theEvent locationInWindow] fromView:nil];
-  const NSRect bounds([self bounds]);
-
-  AutocompleteTextFieldCell* cell = [self cell];
-  const NSRect textFrame([cell textFrameForFrame:bounds]);
-
-  // A version of the textFrame which extends across the field's
-  // entire width.
-
-  const NSRect fullFrame(NSMakeRect(bounds.origin.x, textFrame.origin.y,
-                                    bounds.size.width, textFrame.size.height));
-
-  // If the mouse is in the editing area, or above or below where the
-  // editing area would be if we didn't add decorations, forward to
-  // NSTextField -mouseDown: because it does the right thing.  The
-  // above/below test is needed because NSTextView treats mouse events
-  // above/below as select-to-end-in-that-direction, which makes
-  // things janky.
-  BOOL flipped = [self isFlipped];
-  if (NSMouseInRect(location, textFrame, flipped) ||
-      !NSMouseInRect(location, fullFrame, flipped)) {
-    [super mouseDown:theEvent];
-
-    // After the event has been handled, if the current event is a
-    // mouse up and no selection was created (the mouse didn't move),
-    // select the entire field.
-    // NOTE(shess): This does not interfere with single-clicking to
-    // place caret after a selection is made.  An NSTextField only has
-    // a selection when it has a field editor.  The field editor is an
-    // NSText subview, which will receive the -mouseDown: in that
-    // case, and this code will never fire.
-    NSText* editor = [self currentEditor];
-    if (editor) {
-      NSEvent* currentEvent = [NSApp currentEvent];
-      if ([currentEvent type] == NSLeftMouseUp &&
-          ![editor selectedRange].length) {
-        [editor selectAll:nil];
-      }
-    }
-
-    return;
-  }
-
-  // Give the cell a chance to intercept clicks in page-actions and
-  // other decorative items.
-  if ([cell mouseDown:theEvent inRect:bounds ofView:self]) {
-    return;
-  }
-
-  NSText* editor = [self currentEditor];
-
-  // We should only be here if we accepted first-responder status and
-  // have a field editor.  If one of these fires, it means some
-  // assumptions are being broken.
-  DCHECK(editor != nil);
-  DCHECK([editor isDescendantOf:self]);
-
-  // -becomeFirstResponder does a select-all, which we don't want
-  // because it can lead to a dragged-text situation.  Clear the
-  // selection (any valid empty selection will do).
-  [editor setSelectedRange:NSMakeRange(0, 0)];
-
-  // If the event is to the right of the editing area, scroll the
-  // field editor to the end of the content so that the selection
-  // doesn't initiate from somewhere in the middle of the text.
-  if (location.x > NSMaxX(textFrame)) {
-    [editor scrollRangeToVisible:NSMakeRange([[self stringValue] length], 0)];
-  }
-
-  [editor mouseDown:theEvent];
-}
-
-- (void)mouseUp:(NSEvent*)theEvent {
-  const NSRect bounds([self bounds]);
-  AutocompleteTextFieldCell* cell = [self cell];
-  [cell mouseUp:theEvent inRect:bounds ofView:self];
-}
-
-- (void)rightMouseDown:(NSEvent*)event {
-  if (observer_)
-    observer_->OnMouseDown([event buttonNumber]);
-  [super rightMouseDown:event];
-}
-
-- (void)otherMouseDown:(NSEvent *)event {
-  if (observer_)
-    observer_->OnMouseDown([event buttonNumber]);
-  [super otherMouseDown:event];
-}
-
-// Overridden so that cursor and tooltip rects can be updated.
-- (void)setFrame:(NSRect)frameRect {
-  [super setFrame:frameRect];
-  if (observer_) {
-    observer_->OnFrameChanged();
-  }
-  [self updateMouseTracking];
-}
-
-- (void)setAttributedStringValue:(NSAttributedString*)aString {
-  AutocompleteTextFieldEditor* editor =
-      static_cast<AutocompleteTextFieldEditor*>([self currentEditor]);
-
-  if (!editor) {
-    [super setAttributedStringValue:aString];
-  } else {
-    // The type of the field editor must be AutocompleteTextFieldEditor,
-    // otherwise things won't work.
-    DCHECK([editor isKindOfClass:[AutocompleteTextFieldEditor class]]);
-
-    [editor setAttributedString:aString];
-  }
-}
-
-- (NSUndoManager*)undoManagerForTextView:(NSTextView*)textView {
-  if (!undoManager_.get())
-    undoManager_.reset([[NSUndoManager alloc] init]);
-  return undoManager_.get();
-}
-
-- (void)animateToFrame:(NSRect)frame {
-  [self stopAnimation];
-  NSDictionary* animationDictionary = @{
-    NSViewAnimationTargetKey : self,
-    NSViewAnimationStartFrameKey : [NSValue valueWithRect:[self frame]],
-    NSViewAnimationEndFrameKey : [NSValue valueWithRect:frame]
-  };
-  [resizeAnimation_ setViewAnimations:@[ animationDictionary ]];
-  [resizeAnimation_ startAnimation];
-}
-
-- (void)stopAnimation {
-  if ([resizeAnimation_ isAnimating]) {
-    // [NSViewAnimation stopAnimation] results in advancing the animation to
-    // the end. Since this is almost certainly not the behavior we want, reset
-    // the frame to the current frame.
-    NSRect frame = [self frame];
-    [resizeAnimation_ stopAnimation];
-    [self setFrame:frame];
-  }
-}
-
-- (void)clearUndoChain {
-  [undoManager_ removeAllActions];
-}
-
-- (NSRange)textView:(NSTextView *)aTextView
-    willChangeSelectionFromCharacterRange:(NSRange)oldRange
-    toCharacterRange:(NSRange)newRange {
-  if (observer_)
-    return observer_->SelectionRangeForProposedRange(newRange);
-  return newRange;
-}
-
-- (void)addToolTip:(NSString*)tooltip forRect:(NSRect)aRect {
-  [currentToolTips_ addObject:tooltip];
-  [self addToolTipRect:aRect owner:tooltip userData:nil];
-}
-
-- (NSPoint)bubblePointForDecoration:(LocationBarDecoration*)decoration {
-  // Under MD, dialogs have no arrow and anchor to corner of the location bar
-  // frame, not a specific point within it. See http://crbug.com/566115.
-
-  // Inset the omnibox frame by 2 real pixels. This is done because the border
-  // stroke of the omnibox is inside its frame, but bubbles have no border
-  // stroke. The bubble border is part of the shadow drawn by the window server;
-  // outside the bubble frame. In the Y direction, some of that same "gap" must
-  // be kept, otherwise the "border" stroke from the window server shadow would
-  // be drawn inside the omnibox. But since these insets round to integers when
-  // positioning the window, retina needs to use a zero vertical offset to avoid
-  // insetting an entire DIP. This looks OK, since the bubble border and omnibox
-  // border are still drawn flush. TODO(tapted): Convince the borders to overlap
-  // on retina somehow.
-  const CGFloat kStrokeInsetX = 2 * [self cr_lineWidth];
-  const CGFloat kStrokeInsetY = [self cr_lineWidth] == 1.0 ? 1 : 0;
-  const NSRect frame = NSInsetRect([self bounds], kStrokeInsetX, kStrokeInsetY);
-
-  BOOL isLeftDecoration = [[self cell] isLeftDecoration:decoration];
-  NSPoint point = NSMakePoint(isLeftDecoration ? NSMinX(frame) : NSMaxX(frame),
-                              NSMaxY(frame));
-  return [self convertPoint:point toView:nil];
-}
-
-// TODO(shess): -resetFieldEditorFrameIfNeeded is the place where
-// changes to the cell layout should be flushed.  LocationBarViewMac
-// and ToolbarController are calling this routine directly, and I
-// think they are probably wrong.
-// http://crbug.com/40053
-- (void)updateMouseTracking {
-  // This will force |resetCursorRects| to be called, as it is not to be called
-  // directly.
-  [[self window] invalidateCursorRectsForView:self];
-
-  // |removeAllToolTips| only removes those set on the current NSView, not any
-  // subviews. Unless more tooltips are added to this view, this should suffice
-  // in place of managing a set of NSToolTipTag objects.
-  [self removeAllToolTips];
-
-  // Reload the decoration tooltips.
-  [currentToolTips_ removeAllObjects];
-  [[self cell] updateMouseTrackingAndToolTipsInRect:[self bounds] ofView:self];
-}
-
-// NOTE(shess): http://crbug.com/19116 describes a weird bug which
-// happens when the user runs a Print panel on Leopard.  After that,
-// spurious -controlTextDidBeginEditing notifications are sent when an
-// NSTextField is firstResponder, even though -currentEditor on that
-// field returns nil.  That notification caused significant problems
-// in OmniboxViewMac.  -textDidBeginEditing: was NOT being
-// sent in those cases, so this approach doesn't have the problem.
-- (void)textDidBeginEditing:(NSNotification*)aNotification {
-  [super textDidBeginEditing:aNotification];
-  if (observer_) {
-    observer_->OnDidBeginEditing();
-  }
-}
-
-- (void)textDidEndEditing:(NSNotification *)aNotification {
-  [super textDidEndEditing:aNotification];
-  if (observer_) {
-    observer_->OnDidEndEditing();
-  }
-}
-
-// When the window resigns, make sure the autocomplete popup is no
-// longer visible, since the user's focus is elsewhere.
-- (void)windowDidResignKey:(NSNotification*)notification {
-  DCHECK_EQ([self window], [notification object]);
-  if (observer_)
-    observer_->ClosePopup();
-}
-
-- (void)windowDidResize:(NSNotification*)notification {
-  DCHECK_EQ([self window], [notification object]);
-  if (observer_)
-    observer_->OnFrameChanged();
-}
-
-- (void)viewWillMoveToWindow:(NSWindow*)newWindow {
-  if ([self window]) {
-    NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
-    [nc removeObserver:self
-                  name:NSWindowDidResignKeyNotification
-                object:[self window]];
-    [nc removeObserver:self
-                  name:NSWindowDidResizeNotification
-                object:[self window]];
-    [nc removeObserver:self
-                  name:NSWindowDidChangeScreenNotification
-                object:[self window]];
-  }
-}
-
-- (void)windowDidChangeScreen {
-  // Inform the AutocompleteTextFieldCell's of the coordinate system line
-  // width needed to draw a single-pixel line. This value changes as we move
-  // between Retina and non-Retina displays.
-  [[self cell] setSinglePixelLineWidth:[self cr_lineWidth]];
-  [self setNeedsDisplay];
-}
-
-- (void)updateColorsToMatchTheme {
-  if (![[self window] inIncognitoMode]) {
-    return;
-  }
-
-  // Invert the textfield's colors when Material Design and Incognito and not
-  // a custom theme.
-  bool inDarkMode = [[self window] inIncognitoModeWithSystemTheme];
-  const CGFloat kDarkModeGray = 97 / 255.;
-  [self setBackgroundColor:
-      inDarkMode ? [NSColor colorWithGenericGamma22White:kDarkModeGray
-                                                   alpha:1]
-                 : [NSColor whiteColor]];
-  [self setTextColor:OmniboxViewMac::BaseTextColor(inDarkMode)];
-}
-
-- (void)viewDidMoveToWindow {
-  if (![self window]) {
-    return;
-  }
-
-  // Allow the ToolbarController to take action upon the
-  // AutocompleteTextField being added to the window.
-  BrowserWindowController* browserWindowController =
-      [BrowserWindowController browserWindowControllerForView:self];
-  [[browserWindowController toolbarController] locationBarWasAddedToWindow];
-
-  [self updateColorsToMatchTheme];
-
-  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
-  [nc addObserver:self
-         selector:@selector(windowDidResignKey:)
-             name:NSWindowDidResignKeyNotification
-           object:[self window]];
-  [nc addObserver:self
-         selector:@selector(windowDidResize:)
-             name:NSWindowDidResizeNotification
-           object:[self window]];
-  [nc addObserver:self
-         selector:@selector(windowDidChangeScreen)
-             name:NSWindowDidChangeScreenNotification
-           object:[self window]];
-
-  // Make sure the cell has the current line width.
-  [[self cell] setSinglePixelLineWidth:[self cr_lineWidth]];
-
-  // Only register for drops if not in a popup window. Lazily create the
-  // drop handler when the type of window is known.
-  BrowserWindowController* windowController =
-      [BrowserWindowController browserWindowControllerForView:self];
-  if ([windowController isTabbedWindow])
-      dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);
-}
-
-// NSTextField becomes first responder by installing a "field editor"
-// subview.  Clicks outside the field editor (such as a decoration)
-// will attempt to make the field the first-responder again, which
-// causes a select-all, even if the decoration handles the click.  If
-// the field editor is already in place, don't accept first responder
-// again.  This allows the selection to be unmodified if the click is
-// handled by a decoration or context menu (|-mouseDown:| will still
-// change it if appropriate).
-- (BOOL)acceptsFirstResponder {
-  if ([self currentEditor]) {
-    DCHECK_EQ([self currentEditor], [[self window] firstResponder]);
-    return NO;
-  }
-
-  // If the event is a left-mouse click, and it lands on a decoration, then the
-  // event should not cause the text field to become first responder.
-  NSEvent* event = [NSApp currentEvent];
-  if ([event type] == NSLeftMouseDown) {
-    LocationBarDecoration* decoration =
-        [[self cell] decorationForEvent:event inRect:[self bounds] ofView:self];
-    if (decoration && decoration->AcceptsMousePress() != AcceptsPress::NEVER)
-      return NO;
-  }
-
-  return [super acceptsFirstResponder];
-}
-
-// (Overridden from NSResponder)
-- (BOOL)becomeFirstResponder {
-  BOOL doAccept = [super becomeFirstResponder];
-  if (doAccept) {
-    [[BrowserWindowController browserWindowControllerForView:self]
-        lockToolbarVisibilityForOwner:self
-                        withAnimation:YES];
-
-    // Tells the observer that we get the focus.
-    // But we can't call observer_->OnKillFocus() in resignFirstResponder:,
-    // because the first responder will be immediately set to the field editor
-    // when calling [super becomeFirstResponder], thus we won't receive
-    // resignFirstResponder: anymore when losing focus.
-    [[self cell] handleFocusEvent:[NSApp currentEvent] ofView:self];
-  }
-  return doAccept;
-}
-
-// (Overridden from NSResponder)
-- (BOOL)resignFirstResponder {
-  BOOL doResign = [super resignFirstResponder];
-  if (doResign) {
-    [[BrowserWindowController browserWindowControllerForView:self]
-        releaseToolbarVisibilityForOwner:self
-                           withAnimation:YES];
-  }
-  return doResign;
-}
-
-// (URLDropTarget protocol)
-- (id<URLDropTargetController>)urlDropController {
-  BrowserWindowController* windowController =
-      [BrowserWindowController browserWindowControllerForView:self];
-  return [windowController toolbarController];
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
-  bool canDropAtLocation =
-      [[self cell] canDropAtLocationInWindow:[sender draggingLocation]
-                                      ofView:self];
-  return canDropAtLocation ? [dropHandler_ draggingEntered:sender]
-                           : NSDragOperationNone;
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
-  bool canDropAtLocation =
-      [[self cell] canDropAtLocationInWindow:[sender draggingLocation]
-                                      ofView:self];
-  return canDropAtLocation ? [dropHandler_ draggingUpdated:sender]
-                           : NSDragOperationNone;
-}
-
-// (URLDropTarget protocol)
-- (void)draggingExited:(id<NSDraggingInfo>)sender {
-  return [dropHandler_ draggingExited:sender];
-}
-
-// (URLDropTarget protocol)
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
-  return [dropHandler_ performDragOperation:sender];
-}
-
-- (NSMenu*)decorationMenuForEvent:(NSEvent*)event {
-  AutocompleteTextFieldCell* cell = [self cell];
-  return [cell decorationMenuForEvent:event inRect:[self bounds] ofView:self];
-}
-
-- (ViewID)viewID {
-  return VIEW_ID_OMNIBOX;
-}
-
-// ThemedWindowDrawing implementation.
-
-- (void)windowDidChangeTheme {
-  [self updateColorsToMatchTheme];
-}
-
-- (void)windowDidChangeActive {
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h
deleted file mode 100644
index 5529d371..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_CELL_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_CELL_H_
-
-#include <vector>
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/styled_text_field_cell.h"
-
-@class AutocompleteTextField;
-class LocationBarDecoration;
-
-// AutocompleteTextFieldCell extends StyledTextFieldCell to provide support for
-// certain decorations to be applied to the field.  These are the search hint
-// ("Type to search" on the right-hand side), the keyword hint ("Press [Tab] to
-// search Engine" on the right-hand side), and keyword mode ("Search Engine:" in
-// a button-like token on the left-hand side).
-@interface AutocompleteTextFieldCell : StyledTextFieldCell {
- @private
-  // Decorations which live before and after the text, ordered
-  // from outside in.  Decorations are owned by |LocationBarViewMac|.
-  std::vector<LocationBarDecoration*> leadingDecorations_;
-  std::vector<LocationBarDecoration*> trailingDecorations_;
-
-  // The decoration associated to the current dragging session.
-  LocationBarDecoration* draggedDecoration_;
-
-  // Decorations with tracking areas attached to the AutocompleteTextField.
-  std::vector<LocationBarDecoration*> mouseTrackingDecorations_;
-
-  // If YES then the text field will not draw a focus ring or show the insertion
-  // pointer.
-  BOOL hideFocusState_;
-
-  // YES if this field is shown in a popup window.
-  BOOL isPopupMode_;
-
-  // Retains the NSEvent that caused the controlView to become firstResponder.
-  base::scoped_nsobject<NSEvent> focusEvent_;
-
-  // The coordinate system line width that draws a single pixel line.
-  CGFloat singlePixelLineWidth_;
-}
-
-@property(assign, nonatomic) BOOL isPopupMode;
-@property(assign, nonatomic) CGFloat singlePixelLineWidth;
-
-// Line height used for text in this cell.
-- (CGFloat)lineHeight;
-
-// Remove all of the tracking areas.
-- (void)clearTrackingArea;
-
-// Clear |leftDecorations_| and |rightDecorations_|.
-- (void)clearDecorations;
-
-// Add a new leading decoration after the existing
-// leading decorations.
-- (void)addLeadingDecoration:(LocationBarDecoration*)decoration;
-
-// Add a new trailing decoration before the existing
-// trailing decorations.
-- (void)addTrailingDecoration:(LocationBarDecoration*)decoration;
-
-// The width available after accounting for decorations.
-- (CGFloat)availableWidthInFrame:(const NSRect)frame;
-
-// Return the frame for |aDecoration| if the cell is in |cellFrame|.
-// Returns |NSZeroRect| for decorations which are not currently visible.
-- (NSRect)frameForDecoration:(const LocationBarDecoration*)aDecoration
-                     inFrame:(NSRect)cellFrame;
-
-// Returns whether |decoration| appears on the left or the right side of the
-// text field.
-- (BOOL)isLeftDecoration:(LocationBarDecoration*)decoration;
-
-// Returns true if it's okay to drop dragged data into the view at the
-// given location.
-- (BOOL)canDropAtLocationInWindow:(NSPoint)location
-                           ofView:(AutocompleteTextField*)controlView;
-
-// Find the decoration under the location in the window. Return |NULL| if
-// there's nothing in the location.
-- (LocationBarDecoration*)decorationForLocationInWindow:(NSPoint)location
-                                                 inRect:(NSRect)cellFrame
-                                                 ofView:(AutocompleteTextField*)
-                                                            field;
-
-// Find the decoration under the event.  |NULL| if |theEvent| is not
-// over anything.
-- (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent
-                                      inRect:(NSRect)cellFrame
-                                      ofView:(AutocompleteTextField*)field;
-
-// Return the appropriate menu for any decorations under event.
-// Returns nil if no menu is present for the decoration, or if the
-// event is not over a decoration.
-- (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent
-                           inRect:(NSRect)cellFrame
-                           ofView:(AutocompleteTextField*)controlView;
-
-// Called by |AutocompleteTextField| to let page actions intercept
-// clicks.  Returns |YES| if the click has been intercepted.
-- (BOOL)mouseDown:(NSEvent*)theEvent
-           inRect:(NSRect)cellFrame
-           ofView:(AutocompleteTextField*)controlView;
-
-// Called by |AutocompleteTextField| to pass the mouse up event to the omnibox
-// decorations.
-- (void)mouseUp:(NSEvent*)theEvent
-         inRect:(NSRect)cellFrame
-         ofView:(AutocompleteTextField*)controlView;
-
-// Overridden from StyledTextFieldCell to include decorations adjacent
-// to the text area which don't handle mouse clicks themselves.
-// Keyword-search bubble, for instance.
-- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame;
-
-// Setup decoration tooltips and mouse tracking on |controlView| by calling
-// |-addToolTip:forRect:| and |SetupTrackingArea()|.
-- (void)updateMouseTrackingAndToolTipsInRect:(NSRect)cellFrame
-                                      ofView:
-                                          (AutocompleteTextField*)controlView;
-
-// Gets and sets |hideFocusState|. This allows the text field to have focus but
-// to appear unfocused.
-- (BOOL)hideFocusState;
-- (void)setHideFocusState:(BOOL)hideFocusState
-                   ofView:(AutocompleteTextField*)controlView;
-
-// Handles the |event| that caused |controlView| to become firstResponder.
-- (void)handleFocusEvent:(NSEvent*)event
-                  ofView:(AutocompleteTextField*)controlView;
-
-// Returns the index of |decoration| as a leading decoration, if it is one. The
-// leading-most decoration is at index zero, and increasing indices are closer
-// to the start of the omnibox text field. Returns -1 if |decoration| is not a
-// leading decoration.
-- (int)leadingDecorationIndex:(LocationBarDecoration*)decoration;
-
-@end
-
-// Methods which are either only for testing, or only public for testing.
-@interface AutocompleteTextFieldCell (TestingAPI)
-
-// Returns |mouseTrackingDecorations_|.
-- (const std::vector<LocationBarDecoration*>&)mouseTrackingDecorations;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_CELL_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
deleted file mode 100644
index 3e00eb86..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
+++ /dev/null
@@ -1,786 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
-
-#include <stddef.h>
-
-#include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/mac_logging.h"
-#include "base/stl_util.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#import "extensions/common/feature_switch.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-#import "ui/base/cocoa/appkit_utils.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#include "ui/base/cocoa/scoped_cg_context_smooth_fonts.h"
-#import "ui/base/cocoa/tracking_area.h"
-#include "ui/base/material_design/material_design_controller.h"
-
-using extensions::FeatureSwitch;
-
-namespace {
-
-// Matches the clipping radius of |GradientButtonCell|.
-const CGFloat kCornerRadius = 3.0;
-
-// How far to inset the left- and right-hand decorations from the field's
-// bounds.
-const CGFloat kTrailingDecorationXPadding = 2.0;
-const CGFloat kLeadingDecorationXPadding = 1.0;
-
-// The padding between each decoration on the right.
-const CGFloat kRightDecorationPadding = 1.0f;
-
-// How much the text frame needs to overlap the outermost leading
-// decoration.
-const CGFloat kTextFrameDecorationOverlap = 5.0;
-
-// How long to wait for mouse-up on the location icon before assuming
-// that the user wants to drag.
-const NSTimeInterval kLocationIconDragTimeout = 0.25;
-
-// Calculate the positions for a set of decorations.  |frame| is the
-// overall frame to do layout in, |remaining_frame| will get the
-// left-over space.  |all_decorations| is the set of decorations to
-// lay out, |decorations| will be set to the decorations which are
-// visible and which fit, in the same order as |all_decorations|,
-// while |decoration_frames| will be the corresponding frames.
-// |x_edge| describes the edge to layout the decorations against
-// (|NSMinXEdge| or |NSMaxXEdge|).  |regular_padding| is the padding
-// from the edge of |cell_frame| to use when the first visible decoration
-// is a regular decoration. |decoration_padding| is the padding between each
-// decoration.
-void CalculatePositionsHelper(
-    NSRect frame,
-    const std::vector<LocationBarDecoration*>& all_decorations,
-    NSRectEdge x_edge,
-    CGFloat regular_padding,
-    std::vector<LocationBarDecoration*>* decorations,
-    std::vector<NSRect>* decoration_frames,
-    NSRect* remaining_frame,
-    CGFloat decoration_padding) {
-  DCHECK(x_edge == NSMinXEdge || x_edge == NSMaxXEdge);
-  DCHECK_EQ(decorations->size(), decoration_frames->size());
-
-  // The initial padding depends on whether the first visible decoration is
-  // a button or not.
-  bool is_first_visible_decoration = true;
-
-  for (size_t i = 0; i < all_decorations.size(); ++i) {
-    if (all_decorations[i]->IsVisible()) {
-      CGFloat padding = 0;
-      if (is_first_visible_decoration) {
-        padding = regular_padding;
-        is_first_visible_decoration = false;
-      } else {
-        padding = decoration_padding;
-      }
-
-      NSRect padding_rect, available;
-
-      // Peel off the outside padding.
-      NSDivideRect(frame, &padding_rect, &available, padding, x_edge);
-
-      // Find out how large the decoration will be in the remaining
-      // space.
-      const CGFloat used_width =
-          all_decorations[i]->GetWidthForSpace(NSWidth(available));
-
-      if (used_width != LocationBarDecoration::kOmittedWidth) {
-        DCHECK_GT(used_width, 0.0);
-        NSRect decoration_frame;
-
-        // Peel off the desired width, leaving the remainder in
-        // |frame|.
-        NSDivideRect(available, &decoration_frame, &frame,
-                     used_width, x_edge);
-
-        decorations->push_back(all_decorations[i]);
-        decoration_frames->push_back(decoration_frame);
-        DCHECK_EQ(decorations->size(), decoration_frames->size());
-      }
-    }
-  }
-
-  DCHECK_EQ(decorations->size(), decoration_frames->size());
-  *remaining_frame = frame;
-}
-
-// Helper function for calculating placement of decorations w/in the cell.
-// |frame| is the cell's boundary rectangle, |text_frame| will get any
-// space left after decorations are laid out (for text).
-// |leading_decorations| is a set of decorations for the leading side of
-// the cell, |trailing_decorations| for the right-hand side.
-// |decorations| will contain the resulting visible decorations, and
-// |decoration_frames| will contain their frames in the same coordinates as
-// |frame|.  Decorations will be ordered left to right in LTR, and right to
-// left.
-// As a convenience, returns the index of the first right-hand decoration.
-size_t CalculatePositionsInFrame(
-    const NSRect frame,
-    const std::vector<LocationBarDecoration*>& leading_decorations,
-    const std::vector<LocationBarDecoration*>& trailing_decorations,
-    std::vector<LocationBarDecoration*>* decorations,
-    std::vector<NSRect>* decoration_frames,
-    NSRect* text_frame) {
-  decorations->clear();
-  decoration_frames->clear();
-  *text_frame = frame;
-
-  // Layout |leading_decorations| against the leading side.
-  CalculatePositionsHelper(*text_frame, leading_decorations, NSMinXEdge,
-                           kLeadingDecorationXPadding, decorations,
-                           decoration_frames, text_frame, 0.0f);
-  DCHECK_EQ(decorations->size(), decoration_frames->size());
-
-  // Capture the number of visible leading decorations.
-  size_t leading_count = decorations->size();
-
-  // Extend the text frame so that it slightly overlaps the rightmost left
-  // decoration.
-  if (leading_count) {
-    text_frame->origin.x -= kTextFrameDecorationOverlap;
-    text_frame->size.width += kTextFrameDecorationOverlap;
-  }
-
-  // Layout |trailing_decorations| against the trailing side.
-  CalculatePositionsHelper(*text_frame, trailing_decorations, NSMaxXEdge,
-                           kTrailingDecorationXPadding, decorations,
-                           decoration_frames, text_frame,
-                           kRightDecorationPadding);
-  DCHECK_EQ(decorations->size(), decoration_frames->size());
-
-  // Reverse the right-hand decorations so that overall everything is
-  // sorted left to right.
-  std::reverse(decorations->begin() + leading_count, decorations->end());
-  std::reverse(decoration_frames->begin() + leading_count,
-               decoration_frames->end());
-
-  // Flip all frames in RTL.
-  if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) {
-    for (NSRect& rect : *decoration_frames)
-      rect.origin.x =
-          NSMinX(frame) + NSMaxX(frame) - NSWidth(rect) - NSMinX(rect);
-    text_frame->origin.x = NSMinX(frame) + NSMaxX(frame) -
-                           NSWidth(*text_frame) - NSMinX(*text_frame);
-    leading_count = decorations->size() - leading_count;
-  }
-
-  return leading_count;
-}
-
-}  // namespace
-
-@implementation AutocompleteTextFieldCell
-
-@synthesize isPopupMode = isPopupMode_;
-@synthesize singlePixelLineWidth = singlePixelLineWidth_;
-
-- (CGFloat)topTextFrameOffset {
-  return 3.0;
-}
-
-- (CGFloat)bottomTextFrameOffset {
-  return 3.0;
-}
-
-- (CGFloat)cornerRadius {
-  return kCornerRadius;
-}
-
-- (BOOL)shouldDrawBezel {
-  return YES;
-}
-
-- (CGFloat)lineHeight {
-  return 17;
-}
-
-- (NSText*)setUpFieldEditorAttributes:(NSText*)textObj {
-  NSText* fieldEditor = [super setUpFieldEditorAttributes:textObj];
-
-  // -[NSTextFieldCell setUpFieldEditorAttributes:] matches the field editor's
-  // background to its own background, which can cover our decorations in their
-  // hover state. See https://crbug.com/669870.
-  [fieldEditor setDrawsBackground:NO];
-  return fieldEditor;
-}
-
-- (void)clearTrackingArea {
-  for (auto* decoration : mouseTrackingDecorations_)
-    decoration->RemoveTrackingArea();
-
-  mouseTrackingDecorations_.clear();
-}
-
-- (void)clearDecorations {
-  leadingDecorations_.clear();
-  trailingDecorations_.clear();
-  [self clearTrackingArea];
-}
-
-- (void)addLeadingDecoration:(LocationBarDecoration*)decoration {
-  leadingDecorations_.push_back(decoration);
-}
-
-- (void)addTrailingDecoration:(LocationBarDecoration*)decoration {
-  trailingDecorations_.push_back(decoration);
-}
-
-- (CGFloat)availableWidthInFrame:(const NSRect)frame {
-  std::vector<LocationBarDecoration*> decorations;
-  std::vector<NSRect> decorationFrames;
-  NSRect textFrame;
-  CalculatePositionsInFrame(frame, leadingDecorations_, trailingDecorations_,
-                            &decorations, &decorationFrames, &textFrame);
-
-  return NSWidth(textFrame);
-}
-
-- (NSRect)frameForDecoration:(const LocationBarDecoration*)aDecoration
-                     inFrame:(NSRect)cellFrame {
-  // Short-circuit if the decoration is known to be not visible.
-  if (aDecoration && !aDecoration->IsVisible())
-    return NSZeroRect;
-
-  // Layout the decorations.
-  std::vector<LocationBarDecoration*> decorations;
-  std::vector<NSRect> decorationFrames;
-  NSRect textFrame;
-  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
-                            trailingDecorations_, &decorations,
-                            &decorationFrames, &textFrame);
-
-  // Find our decoration and return the corresponding frame.
-  std::vector<LocationBarDecoration*>::const_iterator iter =
-      std::find(decorations.begin(), decorations.end(), aDecoration);
-  if (iter != decorations.end()) {
-    const size_t index = iter - decorations.begin();
-    return decorationFrames[index];
-  }
-
-  // Decorations which are not visible should have been filtered out
-  // at the top, but return |NSZeroRect| rather than a 0-width rect
-  // for consistency. This can happen while a window is being resized, if it
-  // becomes too small to contain a decoration in the process of shrinking.
-  return NSZeroRect;
-}
-
-- (BOOL)isLeftDecoration:(LocationBarDecoration*)decoration {
-  std::vector<LocationBarDecoration*>& left_decorations =
-      cocoa_l10n_util::ShouldDoExperimentalRTLLayout() ? trailingDecorations_
-                                                       : leadingDecorations_;
-  return base::ContainsValue(left_decorations, decoration);
-}
-
-// Overriden to account for the decorations.
-- (NSRect)textFrameForFrame:(NSRect)cellFrame {
-  // Get the frame adjusted for decorations.
-  std::vector<LocationBarDecoration*> decorations;
-  std::vector<NSRect> decorationFrames;
-  NSRect textFrame = [super textFrameForFrame:cellFrame];
-  CalculatePositionsInFrame(textFrame, leadingDecorations_,
-                            trailingDecorations_, &decorations,
-                            &decorationFrames, &textFrame);
-
-  // The text needs to be slightly higher than its default position to match the
-  // Material Design spec. It turns out this adjustment is equal to the single
-  // pixel line width (so 1 on non-Retina, 0.5 on Retina). Make this adjustment
-  // after computing decoration positions because the decorations are already
-  // correctly positioned. The spec also calls for positioning the text 1pt to
-  // the right of its default position.
-  textFrame.origin.x += 1;
-  textFrame.size.width -= 1;
-  textFrame.origin.y -= singlePixelLineWidth_;
-
-  // NOTE: This function must closely match the logic in
-  // |-drawInteriorWithFrame:inView:|.
-
-  return textFrame;
-}
-
-- (NSRect)textCursorFrameForFrame:(NSRect)cellFrame {
-  std::vector<LocationBarDecoration*> decorations;
-  std::vector<NSRect> decorationFrames;
-  NSRect textFrame;
-  size_t left_count = CalculatePositionsInFrame(
-      cellFrame, leadingDecorations_, trailingDecorations_, &decorations,
-      &decorationFrames, &textFrame);
-
-  // Determine the left-most extent for the i-beam cursor.
-  CGFloat minX = NSMinX(textFrame);
-  for (size_t index = left_count; index--; ) {
-    if (decorations[index]->AcceptsMousePress() != AcceptsPress::NEVER)
-      break;
-
-    // If at leftmost decoration, expand to edge of cell.
-    if (!index)
-      minX = NSMinX(cellFrame);
-    else
-      minX = NSMinX(decorationFrames[index]);
-  }
-
-  // Determine the right-most extent for the i-beam cursor.
-  CGFloat maxX = NSMaxX(textFrame);
-  for (size_t index = left_count; index < decorations.size(); ++index) {
-    if (decorations[index]->AcceptsMousePress() != AcceptsPress::NEVER)
-      break;
-
-    // If at rightmost decoration, expand to edge of cell.
-    if (index == decorations.size() - 1)
-      maxX = NSMaxX(cellFrame);
-    else
-      maxX = NSMaxX(decorationFrames[index]);
-  }
-
-  // I-beam cursor covers left-most to right-most.
-  return NSMakeRect(minX, NSMinY(textFrame), maxX - minX, NSHeight(textFrame));
-}
-
-- (void)drawWithFrame:(NSRect)frame inView:(NSView*)controlView {
-  BOOL inDarkMode = [[controlView window] inIncognitoModeWithSystemTheme];
-  BOOL showingFirstResponder = [self showsFirstResponder];
-
-  // There's a special focus color for incognito, which needs to replace the
-  // border stroke to provide sufficient contrast with focus.
-  NSColor* opaqueFocusColor = inDarkMode
-                                  ? [NSColor colorWithSRGBRed:123 / 255.
-                                                        green:170 / 255.
-                                                         blue:247 / 255.
-                                                        alpha:1]
-                                  : [NSColor keyboardFocusIndicatorColor];
-
-  // Set the border color.
-  const ui::ThemeProvider* provider = [[controlView window] themeProvider];
-  bool increaseContrast = provider && provider->ShouldIncreaseContrast();
-  if (!inDarkMode) {
-    if (increaseContrast) {
-      [[NSColor blackColor] set];
-    } else {
-      const CGFloat kNormalStrokeGray = 168 / 255.;
-      [[NSColor colorWithCalibratedWhite:kNormalStrokeGray alpha:1] set];
-    }
-  } else {
-    if (increaseContrast) {
-      [[NSColor whiteColor] set];
-    } else if (showingFirstResponder) {
-      [opaqueFocusColor set];
-    } else {
-      const CGFloat k30PercentAlpha = 0.3;
-      [[NSColor colorWithCalibratedWhite:0 alpha:k30PercentAlpha] set];
-    }
-  }
-
-  // First, draw the border with a filled rounded rectangle, and draw the
-  // "background" over it to make a stroke. This avoids drawing a stroke with
-  // inner and outer radii that differ by an irrational delta. The stroke is
-  // inset by one screen pixel from the frame to make room for the focus ring,
-  // should it be needed.
-  NSRect rect =
-      NSInsetRect(frame, singlePixelLineWidth_, singlePixelLineWidth_);
-  NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:rect
-                                                       xRadius:kCornerRadius
-                                                       yRadius:kCornerRadius];
-  [path fill];
-
-  // Draw the "background". This will look terrible if it's not opaque. Note
-  // that insetting rounded rectangles also decreases the corner radius,
-  // consistent with SkRRect::inset().
-  DCHECK_EQ(1.0, [[self backgroundColor] alphaComponent]);
-  [[self backgroundColor] set];
-  const CGFloat innerBorderRadius = kCornerRadius - singlePixelLineWidth_;
-  rect =
-      NSInsetRect(frame, 2 * singlePixelLineWidth_, 2 * singlePixelLineWidth_);
-  path = [NSBezierPath bezierPathWithRoundedRect:rect
-                                         xRadius:innerBorderRadius
-                                         yRadius:innerBorderRadius];
-  [path fill];
-
-  // Draw the interior contents. We do this after drawing the border as some
-  // of the interior controls draw over it.
-  [self drawInteriorWithFrame:frame inView:controlView];
-
-  if (!showingFirstResponder)
-    return;
-
-  // Draw the focus ring. It is always 1 real pixel either side of the border.
-  // That is, 3 real pixels wide; filling the frame.
-  constexpr CGFloat kFocusAlpha = 0.5;
-  [[opaqueFocusColor colorWithAlphaComponent:kFocusAlpha] set];
-  const CGFloat outerFocusRadius = kCornerRadius + singlePixelLineWidth_;
-  const CGFloat innerFocusRadius = kCornerRadius - 2 * singlePixelLineWidth_;
-  rect =
-      NSInsetRect(frame, 3 * singlePixelLineWidth_, 3 * singlePixelLineWidth_);
-  path = [NSBezierPath bezierPathWithRoundedRect:rect
-                                         xRadius:innerFocusRadius
-                                         yRadius:innerFocusRadius];
-  [path setWindingRule:NSEvenOddWindingRule];
-  [path appendBezierPath:[NSBezierPath
-                             bezierPathWithRoundedRect:frame
-                                               xRadius:outerFocusRadius
-                                               yRadius:outerFocusRadius]];
-  gfx::ScopedNSGraphicsContextSaveGState scopedGState;
-  [path addClip];
-  // Clipping determines the shape, so just fill.
-  NSRectFillUsingOperation(frame, NSCompositeSourceOver);
-}
-
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
-  ui::ScopedCGContextSmoothFonts fontSmoothing;
-  [super drawInteriorWithFrame:cellFrame inView:controlView];
-
-  // NOTE: This method must closely match the logic in |-textFrameForFrame:|.
-  std::vector<LocationBarDecoration*> decorations;
-  std::vector<NSRect> decorationFrames;
-  NSRect workingFrame;
-
-  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
-                            trailingDecorations_, &decorations,
-                            &decorationFrames, &workingFrame);
-
-  // Draw the decorations. Do this after drawing the interior because the
-  // field editor's background rect overlaps the right edge of the security
-  // decoration's hover rounded rect.
-  for (size_t i = 0; i < decorations.size(); ++i) {
-    if (decorations[i]) {
-      decorations[i]->DrawWithBackgroundInFrame(decorationFrames[i],
-                                                controlView);
-    }
-  }
-}
-
-- (BOOL)canDropAtLocationInWindow:(NSPoint)location
-                           ofView:(AutocompleteTextField*)controlView {
-  NSRect cellFrame = [controlView bounds];
-  const NSPoint locationInView =
-      [controlView convertPoint:location fromView:nil];
-
-  NSRect textFrame;
-  std::vector<LocationBarDecoration*> decorations;
-  std::vector<NSRect> decorationFrames;
-  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
-                            trailingDecorations_, &decorations,
-                            &decorationFrames, &textFrame);
-  return NSPointInRect(locationInView, textFrame);
-}
-
-- (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent
-                                      inRect:(NSRect)cellFrame
-                                      ofView:(AutocompleteTextField*)controlView
-{
-  return [self decorationForLocationInWindow:[theEvent locationInWindow]
-                                      inRect:cellFrame
-                                      ofView:controlView];
-}
-
-- (LocationBarDecoration*)decorationForLocationInWindow:(NSPoint)location
-                                                 inRect:(NSRect)cellFrame
-                                                 ofView:(AutocompleteTextField*)
-                                                            controlView {
-  const BOOL flipped = [controlView isFlipped];
-  const NSPoint locationInView =
-      [controlView convertPoint:location fromView:nil];
-
-  std::vector<LocationBarDecoration*> decorations;
-  std::vector<NSRect> decorationFrames;
-  NSRect textFrame;
-  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
-                            trailingDecorations_, &decorations,
-                            &decorationFrames, &textFrame);
-
-  for (size_t i = 0; i < decorations.size(); ++i) {
-    if (NSMouseInRect(locationInView, decorationFrames[i], flipped))
-      return decorations[i];
-  }
-
-  return NULL;
-}
-
-- (NSMenu*)decorationMenuForEvent:(NSEvent*)theEvent
-                           inRect:(NSRect)cellFrame
-                           ofView:(AutocompleteTextField*)controlView {
-  LocationBarDecoration* decoration =
-      [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView];
-  if (decoration)
-    return decoration->GetMenu();
-  return nil;
-}
-
-- (BOOL)mouseDown:(NSEvent*)theEvent
-           inRect:(NSRect)cellFrame
-           ofView:(AutocompleteTextField*)controlView {
-  // TODO(groby): Factor this into three pieces - find target for event, handle
-  // delayed focus (for any and all events), execute mouseDown for target.
-
-  // Check if this mouseDown was the reason the control became firstResponder.
-  // If not, discard focus event.
-  base::scoped_nsobject<NSEvent> focusEvent(focusEvent_.release());
-  if (![theEvent isEqual:focusEvent])
-    focusEvent.reset();
-
-  LocationBarDecoration* decoration =
-      [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView];
-  if (!decoration || decoration->AcceptsMousePress() == AcceptsPress::NEVER)
-    return NO;
-
-  decoration->OnMouseDown();
-
-  NSRect decorationRect =
-      [self frameForDecoration:decoration inFrame:cellFrame];
-
-  // If the decoration is draggable, then initiate a drag if the user
-  // drags or holds the mouse down for awhile.
-  if (decoration->IsDraggable()) {
-    NSDate* timeout =
-        [NSDate dateWithTimeIntervalSinceNow:kLocationIconDragTimeout];
-    NSEvent* event = [NSApp nextEventMatchingMask:(NSLeftMouseDraggedMask |
-                                                   NSLeftMouseUpMask)
-                                        untilDate:timeout
-                                           inMode:NSEventTrackingRunLoopMode
-                                          dequeue:YES];
-    if (!event || [event type] == NSLeftMouseDragged) {
-      NSPasteboard* pboard = decoration->GetDragPasteboard();
-      DCHECK(pboard);
-
-      NSImage* image = decoration->GetDragImage();
-      DCHECK(image);
-
-      NSRect dragImageRect = decoration->GetDragImageFrame(decorationRect);
-
-      // Center under mouse horizontally, with cursor below so the image
-      // can be seen.
-      const NSPoint mousePoint =
-          [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
-      dragImageRect.origin =
-          NSMakePoint(mousePoint.x - NSWidth(dragImageRect) / 2.0,
-                      mousePoint.y - NSHeight(dragImageRect));
-      draggedDecoration_ = decoration;
-      draggedDecoration_->SetActive(true);
-
-      // -[NSView dragImage:at:*] wants the images lower-left point,
-      // regardless of -isFlipped.  Converting the rect to window base
-      // coordinates doesn't require any special-casing.  Note that
-      // -[NSView dragFile:fromRect:*] takes a rect rather than a
-      // point, likely for this exact reason.
-      const NSPoint dragPoint =
-          [controlView convertRect:dragImageRect toView:nil].origin;
-      [[controlView window] dragImage:image
-                                   at:dragPoint
-                               offset:NSZeroSize
-                                event:theEvent
-                           pasteboard:pboard
-                               source:self
-                            slideBack:YES];
-
-      return YES;
-    }
-
-    // On mouse-up fall through to mouse-pressed case.
-    DCHECK_EQ([event type], NSLeftMouseUp);
-    decoration->OnMouseUp();
-  }
-
-  const NSPoint mouseLocation = [theEvent locationInWindow];
-  const NSPoint point = [controlView convertPoint:mouseLocation fromView:nil];
-  return decoration->HandleMousePressed(
-      decorationRect, NSMakePoint(point.x - decorationRect.origin.x,
-                                  point.y - decorationRect.origin.y));
-}
-
-- (void)mouseUp:(NSEvent*)theEvent
-         inRect:(NSRect)cellFrame
-         ofView:(AutocompleteTextField*)controlView {
-  LocationBarDecoration* decoration =
-      [self decorationForEvent:theEvent inRect:cellFrame ofView:controlView];
-  if (decoration)
-    decoration->OnMouseUp();
-}
-
-// Returns the file path for file |name| if saved at NSURL |base|.
-static NSString* PathWithBaseURLAndName(NSURL* base, NSString* name) {
-  NSString* filteredName =
-      [name stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
-  return [[NSURL URLWithString:filteredName relativeToURL:base] path];
-}
-
-// Returns if there is already a file |name| at dir NSURL |base|.
-static BOOL FileAlreadyExists(NSURL* base, NSString* name) {
-  NSString* path = PathWithBaseURLAndName(base, name);
-  DCHECK([path hasSuffix:name]);
-  return [[NSFileManager defaultManager] fileExistsAtPath:path];
-}
-
-// Takes a destination URL, a suggested file name, & an extension (eg .webloc).
-// Returns the complete file name with extension you should use.
-// The name returned will not contain /, : or ?, will not start with a dot,
-// will not be longer than kMaxNameLength + length of extension, and will not
-// be a file name that already exists in that directory. If necessary it will
-// try appending a space and a number to the name (but before the extension)
-// trying numbers up to and including kMaxIndex.
-// If the function gives up it returns nil.
-static NSString* UnusedLegalNameForNewDropFile(NSURL* saveLocation,
-                                               NSString *fileName,
-                                               NSString *extension) {
-  int number = 1;
-  const int kMaxIndex = 20;
-  const unsigned kMaxNameLength = 64; // Arbitrary.
-
-  NSString* filteredName = [fileName stringByReplacingOccurrencesOfString:@"/"
-                                                               withString:@"-"];
-  filteredName = [filteredName stringByReplacingOccurrencesOfString:@":"
-                                                         withString:@"-"];
-  filteredName = [filteredName stringByReplacingOccurrencesOfString:@"?"
-                                                         withString:@"-"];
-  filteredName =
-      [filteredName stringByReplacingOccurrencesOfString:@"."
-                                              withString:@"-"
-                                                 options:0
-                                                   range:NSMakeRange(0,1)];
-
-  if ([filteredName length] > kMaxNameLength)
-    filteredName = [filteredName substringToIndex:kMaxNameLength];
-
-  NSString* candidateName = [filteredName stringByAppendingString:extension];
-
-  while (FileAlreadyExists(saveLocation, candidateName)) {
-    if (number > kMaxIndex)
-      return nil;
-    else
-      candidateName = [filteredName stringByAppendingFormat:@" %d%@",
-                       number++, extension];
-  }
-
-  return candidateName;
-}
-
-- (NSArray*)namesOfPromisedFilesDroppedAtDestination:(NSURL*)dropDestination {
-  NSPasteboard* pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
-  NSFileManager* fileManager = [NSFileManager defaultManager];
-
-  if (![pboard containsURLDataConvertingTextToURL:YES])
-    return NULL;
-
-  NSArray *urls = NULL;
-  NSArray* titles = NULL;
-  [pboard getURLs:&urls
-                andTitles:&titles
-      convertingFilenames:YES
-      convertingTextToURL:YES];
-
-  NSString* urlStr = [urls objectAtIndex:0];
-  NSString* nameStr = [titles objectAtIndex:0];
-
-  NSString* nameWithExtensionStr =
-      UnusedLegalNameForNewDropFile(dropDestination, nameStr, @".webloc");
-  if (!nameWithExtensionStr)
-    return NULL;
-
-  NSDictionary* urlDict = [NSDictionary dictionaryWithObject:urlStr
-                                                      forKey:@"URL"];
-  NSURL* outputURL =
-      [NSURL fileURLWithPath:PathWithBaseURLAndName(dropDestination,
-                                                    nameWithExtensionStr)];
-  [urlDict writeToURL:outputURL
-           atomically:NO];
-
-  if (![fileManager fileExistsAtPath:[outputURL path]])
-    return NULL;
-
-  NSDictionary* attr = [NSDictionary dictionaryWithObjectsAndKeys:
-      [NSNumber numberWithBool:YES], NSFileExtensionHidden,
-      [NSNumber numberWithUnsignedLong:'ilht'], NSFileHFSTypeCode,
-      [NSNumber numberWithUnsignedLong:'MACS'], NSFileHFSCreatorCode,
-      nil];
-  [fileManager setAttributes:attr
-                ofItemAtPath:[outputURL path]
-                       error:nil];
-
-  return [NSArray arrayWithObject:nameWithExtensionStr];
-}
-
-- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal {
-  return NSDragOperationCopy;
-}
-
-- (void)draggingSession:(NSDraggingSession*)session
-           endedAtPoint:(NSPoint)screenPoint
-              operation:(NSDragOperation)operation {
-  DCHECK(draggedDecoration_);
-  draggedDecoration_->SetActive(false);
-  draggedDecoration_ = nullptr;
-}
-
-- (void)updateMouseTrackingAndToolTipsInRect:(NSRect)cellFrame
-                                      ofView:
-                                          (AutocompleteTextField*)controlView {
-  std::vector<LocationBarDecoration*> decorations;
-  std::vector<NSRect> decorationFrames;
-  NSRect textFrame;
-  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
-                            trailingDecorations_, &decorations,
-                            &decorationFrames, &textFrame);
-  [self clearTrackingArea];
-
-  for (size_t i = 0; i < decorations.size(); ++i) {
-    CrTrackingArea* trackingArea =
-        decorations[i]->SetupTrackingArea(decorationFrames[i], controlView);
-    if (trackingArea)
-      mouseTrackingDecorations_.push_back(decorations[i]);
-
-    NSString* tooltip = decorations[i]->GetToolTip();
-    if ([tooltip length] > 0)
-      [controlView addToolTip:tooltip forRect:decorationFrames[i]];
-  }
-}
-
-- (BOOL)hideFocusState {
-  return hideFocusState_;
-}
-
-- (void)setHideFocusState:(BOOL)hideFocusState
-                   ofView:(AutocompleteTextField*)controlView {
-  if (hideFocusState_ == hideFocusState)
-    return;
-  hideFocusState_ = hideFocusState;
-  [controlView setNeedsDisplay:YES];
-  NSTextView* fieldEditor =
-      base::mac::ObjCCastStrict<NSTextView>([controlView currentEditor]);
-  [fieldEditor updateInsertionPointStateAndRestartTimer:YES];
-}
-
-- (BOOL)showsFirstResponder {
-  return [super showsFirstResponder] && !hideFocusState_;
-}
-
-- (void)handleFocusEvent:(NSEvent*)event
-                  ofView:(AutocompleteTextField*)controlView {
-  if ([controlView observer]) {
-    const bool controlDown = ([event modifierFlags] & NSControlKeyMask) != 0;
-    [controlView observer]->OnSetFocus(controlDown);
-  }
-}
-
-- (int)leadingDecorationIndex:(LocationBarDecoration*)decoration {
-  for (size_t i = 0; i < leadingDecorations_.size(); ++i)
-    if (leadingDecorations_[i] == decoration)
-      return leadingDecorations_.size() - (i + 1);
-  return -1;
-}
-
-@end
-
-@implementation AutocompleteTextFieldCell (TestingAPI)
-
-- (const std::vector<LocationBarDecoration*>&)mouseTrackingDecorations {
-  return mouseTrackingDecorations_;
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
deleted file mode 100644
index d5ccfdaa..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/utf_string_conversions.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#import "chrome/browser/ui/cocoa/test/scoped_force_rtl_mac.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-#include "third_party/ocmock/gtest_support.h"
-#include "ui/base/material_design/material_design_controller.h"
-
-using ::testing::Return;
-using ::testing::StrictMock;
-using ::testing::_;
-
-namespace {
-
-// Width of the field so that we don't have to ask |field_| for it all
-// the time.
-const CGFloat kWidth(300.0);
-
-class MockDecoration : public LocationBarDecoration {
- public:
-  virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
-
-  MOCK_METHOD2(DrawInFrame, void(NSRect frame, NSView* control_view));
-  MOCK_METHOD0(GetToolTip, NSString*());
-};
-
-class AutocompleteTextFieldCellTest : public CocoaTest {
- public:
-  AutocompleteTextFieldCellTest() {
-    // Make sure this is wide enough to play games with the cell
-    // decorations.
-    const NSRect frame = NSMakeRect(0, 0, kWidth, 30);
-
-    base::scoped_nsobject<NSTextField> view(
-        [[NSTextField alloc] initWithFrame:frame]);
-    view_ = view.get();
-
-    base::scoped_nsobject<AutocompleteTextFieldCell> cell(
-        [[AutocompleteTextFieldCell alloc] initTextCell:@"Testing"]);
-    [cell setEditable:YES];
-    [cell setBordered:YES];
-
-    [cell clearDecorations];
-    mock_leading_decoration_.SetVisible(false);
-    [cell addLeadingDecoration:&mock_leading_decoration_];
-    mock_trailing_decoration0_.SetVisible(false);
-    mock_trailing_decoration1_.SetVisible(false);
-    [cell addTrailingDecoration:&mock_trailing_decoration0_];
-    [cell addTrailingDecoration:&mock_trailing_decoration1_];
-
-    [view_ setCell:cell.get()];
-
-    [[test_window() contentView] addSubview:view_];
-  }
-
-  NSTextField* view_;
-  MockDecoration mock_leading_decoration_;
-  MockDecoration mock_trailing_decoration0_;
-  MockDecoration mock_trailing_decoration1_;
-};
-
-// Basic view tests (AddRemove, Display).
-TEST_VIEW(AutocompleteTextFieldCellTest, view_);
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(AutocompleteTextFieldCellTest, FocusedDisplay) {
-  [view_ display];
-
-  // Test focused drawing.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:view_];
-  [view_ display];
-  [test_window() clearPretendKeyWindowAndFirstResponder];
-
-  // Test display of various cell configurations.
-  AutocompleteTextFieldCell* cell =
-      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
-
-  // Load available decorations and try drawing.  To make sure that
-  // they are actually drawn, check that |GetWidthForSpace()| doesn't
-  // indicate that they should be omitted.
-  const CGFloat kVeryWide = 1000.0;
-
-  // Make sure we're actually calling |DrawInFrame()|.
-  StrictMock<MockDecoration> mock_decoration;
-  mock_decoration.SetVisible(true);
-  [cell addLeadingDecoration:&mock_decoration];
-  EXPECT_CALL(mock_decoration, DrawInFrame(_, _));
-  EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide),
-            LocationBarDecoration::kOmittedWidth);
-
-  [view_ display];
-
-  [cell clearDecorations];
-}
-
-TEST_F(AutocompleteTextFieldCellTest, TextFrame) {
-  AutocompleteTextFieldCell* cell =
-      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
-  const NSRect bounds([view_ bounds]);
-  NSRect textFrame;
-
-  // The cursor frame should stay the same throughout.
-  const NSRect cursorFrame([cell textCursorFrameForFrame:bounds]);
-  EXPECT_NSEQ(cursorFrame, bounds);
-
-  // At default settings, everything goes to the text area.
-  textFrame = [cell textFrameForFrame:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(textFrame));
-  EXPECT_TRUE(NSContainsRect(bounds, textFrame));
-  EXPECT_EQ(1, NSMinX(textFrame));
-  EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
-  EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
-
-  // Leading decoration takes up space.
-  mock_leading_decoration_.SetVisible(true);
-  textFrame = [cell textFrameForFrame:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(textFrame));
-  EXPECT_TRUE(NSContainsRect(bounds, textFrame));
-  EXPECT_GT(NSMinX(textFrame), NSMinX(bounds));
-  EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
-}
-
-// The editor frame should be slightly inset from the text frame.
-TEST_F(AutocompleteTextFieldCellTest, DrawingRectForBounds) {
-  AutocompleteTextFieldCell* cell =
-      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
-  const NSRect bounds([view_ bounds]);
-  NSRect textFrame, drawingRect;
-
-  textFrame = [cell textFrameForFrame:bounds];
-  drawingRect = [cell drawingRectForBounds:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(drawingRect));
-  EXPECT_TRUE(NSContainsRect(textFrame, NSInsetRect(drawingRect, 1, 1)));
-
-  // Save the starting frame for after clear.
-  const NSRect originalDrawingRect = drawingRect;
-
-  mock_leading_decoration_.SetVisible(true);
-  textFrame = [cell textFrameForFrame:bounds];
-  drawingRect = [cell drawingRectForBounds:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(drawingRect));
-  EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
-
-  mock_trailing_decoration0_.SetVisible(true);
-  textFrame = [cell textFrameForFrame:bounds];
-  drawingRect = [cell drawingRectForBounds:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(drawingRect));
-  EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
-
-  mock_leading_decoration_.SetVisible(false);
-  mock_trailing_decoration0_.SetVisible(false);
-  drawingRect = [cell drawingRectForBounds:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(drawingRect));
-  EXPECT_NSEQ(drawingRect, originalDrawingRect);
-}
-
-// Test that leading decorations are at the correct edge of the cell.
-TEST_F(AutocompleteTextFieldCellTest, LeadingDecorationFrame) {
-  AutocompleteTextFieldCell* cell =
-      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
-  const NSRect bounds = [view_ bounds];
-
-  mock_leading_decoration_.SetVisible(true);
-  const NSRect decorationRect =
-      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(decorationRect));
-  EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
-
-  // Decoration should be left of |drawingRect|.
-  const NSRect drawingRect = [cell drawingRectForBounds:bounds];
-  EXPECT_GT(NSMinX(drawingRect), NSMinX(decorationRect));
-
-  // Decoration should be left of |textFrame|.
-  const NSRect textFrame = [cell textFrameForFrame:bounds];
-  EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect));
-}
-
-// Test that trailing decorations are at the correct edge of the cell.
-TEST_F(AutocompleteTextFieldCellTest, TrailingDecorationFrame) {
-  AutocompleteTextFieldCell* cell =
-      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
-  const NSRect bounds = [view_ bounds];
-
-  mock_trailing_decoration0_.SetVisible(true);
-  mock_trailing_decoration1_.SetVisible(true);
-
-  const NSRect decoration0Rect =
-      [cell frameForDecoration:&mock_trailing_decoration0_ inFrame:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
-  EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
-
-  // Trailing decorations are ordered from innermost to outermost.
-  // Outer decoration (0) to right of inner decoration (1).
-  const NSRect decoration1Rect =
-      [cell frameForDecoration:&mock_trailing_decoration1_ inFrame:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
-  EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
-  EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
-
-  // Decoration should be right of |drawingRect|.
-  const NSRect drawingRect = [cell drawingRectForBounds:bounds];
-  EXPECT_LT(NSMinX(drawingRect), NSMinX(decoration1Rect));
-
-  // Decoration should be right of |textFrame|.
-  const NSRect textFrame = [cell textFrameForFrame:bounds];
-  EXPECT_LT(NSMinX(textFrame), NSMinX(decoration1Rect));
-}
-
-// Verify -[AutocompleteTextFieldCell
-// updateMouseTrackingAndToolTipsInRect:ofView:].
-TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) {
-  NSString* tooltip = @"tooltip";
-
-  // Leading decoration returns a tooltip, make sure it is called at
-  // least once.
-  mock_leading_decoration_.SetVisible(true);
-  EXPECT_CALL(mock_leading_decoration_, GetToolTip())
-      .WillOnce(Return(tooltip))
-      .WillRepeatedly(Return(tooltip));
-
-  // Right decoration returns no tooltip, make sure it is called at
-  // least once.
-  mock_trailing_decoration0_.SetVisible(true);
-  EXPECT_CALL(mock_trailing_decoration0_, GetToolTip())
-      .WillOnce(Return((NSString*)nil))
-      .WillRepeatedly(Return((NSString*)nil));
-
-  AutocompleteTextFieldCell* cell =
-      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
-  const NSRect bounds = [view_ bounds];
-  const NSRect leadingDecorationRect =
-      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
-
-  // |controlView| gets the tooltip for the leading decoration.
-  id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]];
-  [[controlView expect] addToolTip:tooltip forRect:leadingDecorationRect];
-
-  [cell updateMouseTrackingAndToolTipsInRect:bounds ofView:controlView];
-
-  EXPECT_OCMOCK_VERIFY(controlView);
-}
-
-class AutocompleteTextFieldCellTestRTL : public AutocompleteTextFieldCellTest {
- private:
-  cocoa_l10n_util::ScopedForceRTLMac rtl_;
-};
-
-// Test that leading decorations are at the correct edge of the cell.
-TEST_F(AutocompleteTextFieldCellTestRTL, LeadingDecorationFrame) {
-  AutocompleteTextFieldCell* cell =
-      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
-  const NSRect bounds = [view_ bounds];
-
-  mock_leading_decoration_.SetVisible(true);
-  const NSRect decorationRect =
-      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(decorationRect));
-  EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
-  // Decoration should be right of |drawingRect|.
-  const NSRect drawingRect = [cell drawingRectForBounds:bounds];
-  EXPECT_LT(NSMinX(drawingRect), NSMinX(decorationRect));
-
-  // Decoration should be right of |textFrame|.
-  const NSRect textFrame = [cell textFrameForFrame:bounds];
-  EXPECT_LT(NSMinX(textFrame), NSMinX(decorationRect));
-}
-
-// Test that trailing decorations are at the correct edge of the cell.
-TEST_F(AutocompleteTextFieldCellTestRTL, TrailingDecorationFrame) {
-  AutocompleteTextFieldCell* cell =
-      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
-  const NSRect bounds = [view_ bounds];
-
-  mock_trailing_decoration0_.SetVisible(true);
-  mock_trailing_decoration1_.SetVisible(true);
-
-  const NSRect decoration0Rect =
-      [cell frameForDecoration:&mock_trailing_decoration0_ inFrame:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
-  EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
-
-  // Trailing decorations are ordered from front to back..
-  // Outer decoration (0) to the left of inner decoration (1).
-  const NSRect decoration1Rect =
-      [cell frameForDecoration:&mock_trailing_decoration1_ inFrame:bounds];
-  EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
-  EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
-  EXPECT_GT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
-
-  // Decoration should be left of |drawingRect|.
-  const NSRect drawingRect = [cell drawingRectForBounds:bounds];
-  EXPECT_GT(NSMinX(drawingRect), NSMinX(decoration1Rect));
-
-  // Decoration should be left of |textFrame|.
-  const NSRect textFrame = [cell textFrameForFrame:bounds];
-  EXPECT_GT(NSMinX(textFrame), NSMinX(decoration1Rect));
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h
deleted file mode 100644
index adaa98fa..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_EDITOR_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_EDITOR_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#import "chrome/browser/ui/cocoa/url_drop_target.h"
-
-@class AutocompleteTextField;
-class AutocompleteTextFieldObserver;
-
-// AutocompleteTextFieldEditor customized the AutocompletTextField
-// field editor (helper text-view used in editing).  It intercepts UI
-// events for forwarding to the core Omnibox code.  It also undoes
-// some of the effects of using styled text in the Omnibox (the text
-// is styled but should not appear that way when copied to the
-// pasteboard).
-
-// Field editor used for the autocomplete field.
-@interface AutocompleteTextFieldEditor : NSTextView<URLDropTarget,
-                                                    ThemedWindowDrawing> {
-  // Handles being a drag-and-drop target. We handle DnD directly instead
-  // allowing the |AutocompletTextField| to handle it (by making an empty
-  // |-updateDragTypeRegistration|), since the latter results in a weird
-  // start-up time regression.
-  base::scoped_nsobject<URLDropTargetHandler> dropHandler_;
-
-  base::scoped_nsobject<NSCharacterSet> forbiddenCharacters_;
-
-  // Indicates if the field editor's interpretKeyEvents: method is being called.
-  // If it's YES, then we should postpone the call to the observer's
-  // OnDidChange() method after the field editor's interpretKeyEvents: method
-  // is finished, rather than calling it in textDidChange: method. Because the
-  // input method may update the marked text after inserting some text, but we
-  // need the observer be aware of the marked text as well.
-  BOOL interpretingKeyEvents_;
-
-  // Indicates if the text has been changed by key events.
-  BOOL textChangedByKeyEvents_;
-}
-
-// The delegate is always an AutocompleteTextField*.  Override the superclass
-// implementations to allow for proper typing.
-- (AutocompleteTextField*)delegate;
-- (void)setDelegate:(AutocompleteTextField*)delegate;
-
-// Sets attributed string programatically through the field editor's text
-// storage object.
-- (void)setAttributedString:(NSAttributedString*)aString;
-
-@end
-
-@interface AutocompleteTextFieldEditor(PrivateTestMethods)
-- (AutocompleteTextFieldObserver*)observer;
-- (void)pasteAndGo:sender;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_EDITOR_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
deleted file mode 100644
index 3b2ff88..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.mm
+++ /dev/null
@@ -1,616 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
-
-#include "base/mac/sdk_forward_declarations.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "chrome/app/chrome_command_ids.h"  // IDC_*
-#include "chrome/browser/themes/theme_service.h"
-#include "chrome/browser/ui/browser_list.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
-#include "chrome/grit/generated_resources.h"
-#import "ui/base/cocoa/find_pasteboard.h"
-#import "ui/base/cocoa/touch_bar_forward_declarations.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/material_design/material_design_controller.h"
-
-namespace {
-
-// Set to true when an instance of this class is running a nested run loop.
-// Since this must always be run on the UI thread, there should never be two
-// simultaneous drags.
-bool gInDrag = false;
-
-// When too much data is put into a single-line text field, things get
-// janky due to the cost of computing the blink rect.  Sometimes users
-// accidentally paste large amounts, so place a limit on what will be
-// accepted.
-//
-// 10k characters was arbitrarily chosen by seeing how much a text
-// field could handle in a single line before it started getting too
-// janky to recover from (jankiness was detectable around 5k).
-// www.google.com returns an error for searches around 2k characters,
-// so this is conservative.
-const NSUInteger kMaxPasteLength = 10000;
-
-// Returns |YES| if too much text would be pasted.
-BOOL ThePasteboardIsTooDamnBig() {
-  NSPasteboard* pb = [NSPasteboard generalPasteboard];
-  NSString* type =
-      [pb availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]];
-  if (!type)
-    return NO;
-
-  return [[pb stringForType:type] length] > kMaxPasteLength;
-}
-
-// Returns a possibly disabled "Paste and {Go, Search}" menu item.
-NSMenuItem* PasteAndGoMenuItemForObserver(
-    AutocompleteTextFieldObserver* observer) {
-  DCHECK(observer);
-  int string_id = IDS_PASTE_AND_GO;
-  BOOL enabled = !ThePasteboardIsTooDamnBig() && observer->CanPasteAndGo();
-  if (enabled)
-    string_id = observer->GetPasteActionStringId();
-
-  NSString* title = l10n_util::GetNSStringWithFixup(string_id);
-  base::scoped_nsobject<NSMenuItem> item([[NSMenuItem alloc]
-      initWithTitle:title
-             action:@selector(pasteAndGo:)
-      keyEquivalent:@""]);
-  [item setEnabled:enabled];
-  return item.autorelease();
-}
-
-}  // namespace
-
-@interface AutocompleteTextFieldEditor ()<NSDraggingSource>
-@end
-
-@implementation AutocompleteTextFieldEditor
-
-- (BOOL)shouldDrawInsertionPoint {
-  return [super shouldDrawInsertionPoint] &&
-         ![[[self delegate] cell] hideFocusState];
-}
-
-- (id)initWithFrame:(NSRect)frameRect {
-  if ((self = [super initWithFrame:frameRect])) {
-    dropHandler_.reset([[URLDropTargetHandler alloc] initWithView:self]);
-
-    forbiddenCharacters_.reset([[NSCharacterSet controlCharacterSet] retain]);
-
-    // Disable all substitutions by default. In regular NSTextFields a user may
-    // selectively enable them via context menu, but that submenu is not enabled
-    // for the omnibox. The substitutions are unlikely to be useful in any case.
-    //
-    // Also see http://crbug.com/173405 and http://crbug.com/528014.
-    NSTextCheckingTypes checkingTypes = 0;
-    [self setEnabledTextCheckingTypes:checkingTypes];
-  }
-  return self;
-}
-
-// Overridden to prevent unwanted items from appearing in the Touch Bar.
-- (NSTouchBar*)makeTouchBar {
-  return nil;
-}
-
-- (void)updateColorsToMatchTheme {
-  if (![[self window] inIncognitoMode]) {
-    return;
-  }
-
-  bool inDarkMode = [[self window] inIncognitoModeWithSystemTheme];
-  // Draw a white insertion point for MD Incognito.
-  NSColor* insertionPointColor =
-      inDarkMode ? [NSColor whiteColor] : [NSColor blackColor];
-  [self setInsertionPointColor:insertionPointColor];
-
-  NSColor* textSelectionColor = [NSColor selectedTextBackgroundColor];
-  if (inDarkMode) {
-    // In MD Incognito the text is light gray against a dark background. When
-    // selected, the light gray text against the selection color is illegible.
-    // Rather than tweak or change the selection color, make the text black when
-    // selected.
-    [self setSelectedTextAttributes:@{
-      NSForegroundColorAttributeName : [NSColor blackColor],
-      NSBackgroundColorAttributeName : textSelectionColor
-    }];
-  } else {
-    [self setSelectedTextAttributes:@{
-      NSBackgroundColorAttributeName : textSelectionColor
-    }];
-  }
-}
-
-- (void)viewDidMoveToWindow {
-  // Only care about landing in a window.
-  if ([self window]) {
-    [self updateColorsToMatchTheme];
-  }
-}
-
-// If the entire field is selected, drag the same data as would be
-// dragged from the field's location icon.  In some cases the textual
-// contents will not contain relevant data (for instance, "http://" is
-// stripped from URLs).
-- (BOOL)dragSelectionWithEvent:(NSEvent *)event
-                        offset:(NSSize)mouseOffset
-                     slideBack:(BOOL)slideBack {
-  AutocompleteTextFieldObserver* observer = [self observer];
-  DCHECK(observer);
-  if (observer && observer->CanCopy()) {
-    NSPoint p;
-    NSImage* image = [self dragImageForSelectionWithEvent:event origin:&p];
-
-    base::scoped_nsobject<NSPasteboardItem> item(
-        observer->CreatePasteboardItem());
-    base::scoped_nsobject<NSDraggingItem> dragItem(
-        [[NSDraggingItem alloc] initWithPasteboardWriter:item]);
-    NSRect draggingFrame =
-        NSMakeRect(0, 0, image.size.width, image.size.height);
-    [dragItem setDraggingFrame:draggingFrame contents:image];
-    [self beginDraggingSessionWithItems:@[ dragItem.get() ]
-                                  event:event
-                                 source:self];
-    DCHECK(!gInDrag);
-    gInDrag = true;
-    while (gInDrag) {
-      [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
-                               beforeDate:[NSDate distantFuture]];
-    }
-
-    return YES;
-  }
-  return [super dragSelectionWithEvent:event
-                                offset:mouseOffset
-                             slideBack:slideBack];
-}
-
-- (void)draggingSession:(NSDraggingSession*)session
-           endedAtPoint:(NSPoint)aPoint
-              operation:(NSDragOperation)operation {
-  gInDrag = false;
-}
-
-- (void)copy:(id)sender {
-  AutocompleteTextFieldObserver* observer = [self observer];
-  DCHECK(observer);
-  if (observer && observer->CanCopy())
-    observer->CopyToPasteboard([NSPasteboard generalPasteboard]);
-}
-
-- (void)cut:(id)sender {
-  [self copy:sender];
-  [self delete:nil];
-}
-
-// This class assumes that the delegate is an AutocompleteTextField.
-// Enforce that assumption.
-- (AutocompleteTextField*)delegate {
-  AutocompleteTextField* delegate =
-      static_cast<AutocompleteTextField*>([super delegate]);
-  DCHECK(delegate == nil ||
-         [delegate isKindOfClass:[AutocompleteTextField class]]);
-  return delegate;
-}
-
-- (void)setDelegate:(AutocompleteTextField*)delegate {
-  DCHECK(delegate == nil ||
-         [delegate isKindOfClass:[AutocompleteTextField class]]);
-
-  // Unregister from any previously registered undo and redo notifications.
-  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
-  [nc removeObserver:self
-                name:NSUndoManagerDidUndoChangeNotification
-              object:nil];
-  [nc removeObserver:self
-                name:NSUndoManagerDidRedoChangeNotification
-              object:nil];
-
-  // Set the delegate.
-  [super setDelegate:delegate];
-
-  // Register for undo and redo notifications from the new |delegate|, if it is
-  // non-nil.
-  if ([self delegate]) {
-    NSUndoManager* undo_manager = [self undoManager];
-    [nc addObserver:self
-           selector:@selector(didUndoOrRedo:)
-               name:NSUndoManagerDidUndoChangeNotification
-             object:undo_manager];
-    [nc addObserver:self
-           selector:@selector(didUndoOrRedo:)
-               name:NSUndoManagerDidRedoChangeNotification
-             object:undo_manager];
-  }
-}
-
-- (void)didUndoOrRedo:(NSNotification *)aNotification {
-  AutocompleteTextFieldObserver* observer = [self observer];
-  if (observer)
-    observer->OnDidChange();
-}
-
-// Convenience method for retrieving the observer from the delegate.
-- (AutocompleteTextFieldObserver*)observer {
-  return [[self delegate] observer];
-}
-
-- (void)paste:(id)sender {
-  if (ThePasteboardIsTooDamnBig()) {
-    NSBeep();
-    return;
-  }
-
-  AutocompleteTextFieldObserver* observer = [self observer];
-  DCHECK(observer);
-  if (observer) {
-    observer->OnPaste();
-  }
-}
-
-- (void)pasteAndMatchStyle:(id)sender {
-  [self paste:sender];
-}
-
-- (void)pasteAndGo:sender {
-  if (ThePasteboardIsTooDamnBig()) {
-    NSBeep();
-    return;
-  }
-
-  AutocompleteTextFieldObserver* observer = [self observer];
-  DCHECK(observer);
-  if (observer) {
-    observer->OnPasteAndGo();
-  }
-}
-
-// We have rich text, but it shouldn't be modified by the user, so
-// don't update the font panel.  In theory, -setUsesFontPanel: should
-// accomplish this, but that gets called frequently with YES when
-// NSTextField and NSTextView synchronize their contents.  That is
-// probably unavoidable because in most cases having rich text in the
-// field you probably would expect it to update the font panel.
-- (void)updateFontPanel {}
-
-// No ruler bar, so don't update any of that state, either.
-- (void)updateRuler {}
-
-- (NSMenu*)menuForEvent:(NSEvent*)event {
-  // Give the control a chance to provide page-action menus.
-  // NOTE: Note that page actions aren't even in the editor's
-  // boundaries!  The Cocoa control implementation seems to do a
-  // blanket forward to here if nothing more specific is returned from
-  // the control and cell calls.
-  // TODO(shess): Determine if the page-action part of this can be
-  // moved to the cell.
-  NSMenu* actionMenu = [[self delegate] decorationMenuForEvent:event];
-  if (actionMenu)
-    return actionMenu;
-
-  NSMenu* menu = [[[NSMenu alloc] initWithTitle:@"TITLE"] autorelease];
-  [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_CUT)
-                  action:@selector(cut:)
-           keyEquivalent:@""];
-  [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_COPY)
-                  action:@selector(copy:)
-           keyEquivalent:@""];
-
-  [menu addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_PASTE)
-                  action:@selector(paste:)
-           keyEquivalent:@""];
-
-  if ([self isEditable]) {
-    [menu addItem:PasteAndGoMenuItemForObserver([self observer])];
-    [menu addItem:[NSMenuItem separatorItem]];
-
-    NSString* searchEngineLabel =
-        l10n_util::GetNSStringWithFixup(IDS_EDIT_SEARCH_ENGINES);
-    DCHECK([searchEngineLabel length]);
-    NSMenuItem* item = [menu addItemWithTitle:searchEngineLabel
-                                       action:@selector(commandDispatch:)
-                                keyEquivalent:@""];
-    [item setTag:IDC_EDIT_SEARCH_ENGINES];
-  }
-
-  return menu;
-}
-
-// (Overridden from NSResponder)
-- (BOOL)becomeFirstResponder {
-  BOOL doAccept = [super becomeFirstResponder];
-  AutocompleteTextField* field = [self delegate];
-  // Only lock visibility if we've been set up with a delegate (the text field).
-  if (doAccept && field) {
-    // Give the text field ownership of the visibility lock. (The first
-    // responder dance between the field and the field editor is a little
-    // weird.)
-    [[BrowserWindowController browserWindowControllerForView:field]
-        lockToolbarVisibilityForOwner:field
-                        withAnimation:YES];
-  }
-  return doAccept;
-}
-
-// (Overridden from NSResponder)
-- (BOOL)resignFirstResponder {
-  BOOL doResign = [super resignFirstResponder];
-  AutocompleteTextField* field = [self delegate];
-  // Only lock visibility if we've been set up with a delegate (the text field).
-  if (doResign && field) {
-    // Give the text field ownership of the visibility lock.
-    [[BrowserWindowController browserWindowControllerForView:field]
-        releaseToolbarVisibilityForOwner:field
-                           withAnimation:YES];
-
-    AutocompleteTextFieldObserver* observer = [self observer];
-    if (observer)
-      observer->OnKillFocus();
-  }
-  return doResign;
-}
-
-- (void)mouseDown:(NSEvent*)event {
-  AutocompleteTextFieldObserver* observer = [self observer];
-  if (observer)
-    observer->OnMouseDown([event buttonNumber]);
-  [super mouseDown:event];
-}
-
-- (void)rightMouseDown:(NSEvent *)event {
-  AutocompleteTextFieldObserver* observer = [self observer];
-  if (observer)
-    observer->OnMouseDown([event buttonNumber]);
-  [super rightMouseDown:event];
-}
-
-- (void)otherMouseDown:(NSEvent *)event {
-  AutocompleteTextFieldObserver* observer = [self observer];
-  if (observer)
-    observer->OnMouseDown([event buttonNumber]);
-  [super otherMouseDown:event];
-}
-
-// (URLDropTarget protocol)
-- (id<URLDropTargetController>)urlDropController {
-  BrowserWindowController* windowController =
-      [BrowserWindowController browserWindowControllerForView:self];
-  return [windowController toolbarController];
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
-  // Make ourself the first responder (even though we're presumably already the
-  // first responder), which will select the text to indicate that our contents
-  // would be replaced by a drop.
-  [[self window] makeFirstResponder:self];
-  return [dropHandler_ draggingEntered:sender];
-}
-
-// (URLDropTarget protocol)
-- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender {
-  return [dropHandler_ draggingUpdated:sender];
-}
-
-// (URLDropTarget protocol)
-- (void)draggingExited:(id<NSDraggingInfo>)sender {
-  return [dropHandler_ draggingExited:sender];
-}
-
-// (URLDropTarget protocol)
-- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
-  return [dropHandler_ performDragOperation:sender];
-}
-
-// Prevent control characters from being entered into the Omnibox.
-// This is invoked for keyboard entry, not for pasting.
-- (void)insertText:(id)aString {
-  AutocompleteTextFieldObserver* observer = [self observer];
-  if (observer)
-    observer->OnInsertText();
-
-  // Repeatedly remove control characters.  The loop will only ever
-  // execute at all when the user enters control characters (using
-  // Ctrl-Alt- or Ctrl-Q).  Making this generally efficient would
-  // probably be a loss, since the input always seems to be a single
-  // character.
-  if ([aString isKindOfClass:[NSAttributedString class]]) {
-    NSRange range =
-        [[aString string] rangeOfCharacterFromSet:forbiddenCharacters_];
-    while (range.location != NSNotFound) {
-      aString = [[aString mutableCopy] autorelease];
-      [aString deleteCharactersInRange:range];
-      range = [[aString string] rangeOfCharacterFromSet:forbiddenCharacters_];
-    }
-    DCHECK_EQ(range.length, 0U);
-  } else {
-    NSRange range = [aString rangeOfCharacterFromSet:forbiddenCharacters_];
-    while (range.location != NSNotFound) {
-      aString =
-          [aString stringByReplacingCharactersInRange:range withString:@""];
-      range = [aString rangeOfCharacterFromSet:forbiddenCharacters_];
-    }
-    DCHECK_EQ(range.length, 0U);
-  }
-
-  // NOTE: If |aString| is empty, this intentionally replaces the
-  // selection with empty.  This seems consistent with the case where
-  // the input contained a mixture of characters and the string ended
-  // up not empty.
-  [super insertText:aString];
-}
-
-- (NSRange)selectionRangeForProposedRange:(NSRange)proposedSelRange
-                              granularity:(NSSelectionGranularity)granularity {
-  AutocompleteTextFieldObserver* observer = [self observer];
-  NSRange modifiedRange = [super selectionRangeForProposedRange:proposedSelRange
-                                                    granularity:granularity];
-  if (observer)
-    return observer->SelectionRangeForProposedRange(modifiedRange);
-  return modifiedRange;
-}
-
-- (void)setSelectedRange:(NSRange)charRange
-                affinity:(NSSelectionAffinity)affinity
-          stillSelecting:(BOOL)flag {
-  [super setSelectedRange:charRange affinity:affinity stillSelecting:flag];
-
-  // We're only interested in selection changes directly caused by keyboard
-  // input from the user.
-  if (interpretingKeyEvents_)
-    textChangedByKeyEvents_ = YES;
-}
-
-- (void)interpretKeyEvents:(NSArray *)eventArray {
-  DCHECK(!interpretingKeyEvents_);
-  interpretingKeyEvents_ = YES;
-  textChangedByKeyEvents_ = NO;
-  AutocompleteTextFieldObserver* observer = [self observer];
-
-  if (observer)
-    observer->OnBeforeChange();
-
-  [super interpretKeyEvents:eventArray];
-
-  if (textChangedByKeyEvents_ && observer)
-    observer->OnDidChange();
-
-  DCHECK(interpretingKeyEvents_);
-  interpretingKeyEvents_ = NO;
-
-  // -[NSTextView interpretKeyEvents:] invalidates the existing layout.
-  //
-  // observer->OnDidChange() calls OmniboxViewMac::ApplyTextStyle, which
-  // invalidates the existing layout again, but in a slightly different way.
-  // Details unclear.
-  //
-  // On older versions of macOS, this results in a single call to -[NSTextView
-  // drawRect:] on the next frame, which paints the correct contents.
-  //
-  // On macOS 10.12 dp4, for unknown reasons, this causes two calls to
-  // -[NSTextView drawRect:] across two(!) frames. The first call to
-  // -[NSTextView drawRect:] draws no text, which causes a flicker in the
-  // omnibox. Forcing a layout ensures that drawRect: is only called once, and
-  // is drawn with the correct contents.
-  // https://crbug.com/634318.
-  [self.layoutManager
-      ensureLayoutForCharacterRange:NSMakeRange(0, self.textStorage.length)];
-}
-
-- (BOOL)shouldChangeTextInRange:(NSRange)affectedCharRange
-              replacementString:(NSString *)replacementString {
-  BOOL ret = [super shouldChangeTextInRange:affectedCharRange
-                          replacementString:replacementString];
-
-  if (ret && !interpretingKeyEvents_) {
-    AutocompleteTextFieldObserver* observer = [self observer];
-    if (observer)
-      observer->OnBeforeChange();
-  }
-  return ret;
-}
-
-- (void)didChangeText {
-  [super didChangeText];
-
-  AutocompleteTextFieldObserver* observer = [self observer];
-  if (observer) {
-    if (!interpretingKeyEvents_ &&
-        ![[self undoManager] isUndoing] && ![[self undoManager] isRedoing]) {
-      observer->OnDidChange();
-    } else if (interpretingKeyEvents_) {
-      textChangedByKeyEvents_ = YES;
-    }
-  }
-}
-
-- (void)doCommandBySelector:(SEL)cmd {
-  // TODO(shess): Review code for cases where we're fruitlessly attempting to
-  // work in spite of not having an observer.
-  AutocompleteTextFieldObserver* observer = [self observer];
-
-  if (observer && observer->OnDoCommandBySelector(cmd)) {
-    // The observer should already be aware of any changes to the text, so
-    // setting |textChangedByKeyEvents_| to NO to prevent its OnDidChange()
-    // method from being called unnecessarily.
-    textChangedByKeyEvents_ = NO;
-    return;
-  }
-
-  // If the escape key was pressed and no revert happened, give focus to the web
-  // contents. In fullscreen, this will dismiss the overlay.
-  if (cmd == @selector(cancelOperation:)) {
-    BrowserWindowController* windowController =
-        [BrowserWindowController browserWindowControllerForView:self];
-    [windowController focusTabContents];
-    textChangedByKeyEvents_ = NO;
-    return;
-  }
-
-  [super doCommandBySelector:cmd];
-}
-
-- (void)setAttributedString:(NSAttributedString*)aString {
-  NSTextStorage* textStorage = [self textStorage];
-  DCHECK(textStorage);
-  [textStorage setAttributedString:aString];
-
-  // The text has been changed programmatically. The observer should know
-  // this change, so setting |textChangedByKeyEvents_| to NO to
-  // prevent its OnDidChange() method from being called unnecessarily.
-  textChangedByKeyEvents_ = NO;
-}
-
-- (BOOL)validateMenuItem:(NSMenuItem*)item {
-  if ([item action] == @selector(copyToFindPboard:))
-    return [self selectedRange].length > 0;
-
-  // Paste & Go doesn't appear in the mainMenu. Use the enabled state when the
-  // menu item was added in -menuForEvent:.
-  if ([item action] == @selector(pasteAndGo:))
-    return [item isEnabled];
-
-  return [super validateMenuItem:item];
-}
-
-- (void)copyToFindPboard:(id)sender {
-  NSRange selectedRange = [self selectedRange];
-  if (selectedRange.length == 0)
-    return;
-  NSAttributedString* selection =
-      [self attributedSubstringForProposedRange:selectedRange
-                                    actualRange:NULL];
-  if (!selection)
-    return;
-
-  [[FindPasteboard sharedInstance] setFindText:[selection string]];
-}
-
-- (void)drawRect:(NSRect)rect {
-  AutocompleteTextFieldObserver* observer = [self observer];
-  if (observer)
-    observer->OnBeforeDrawRect();
-  [super drawRect:rect];
-  if (observer)
-    observer->OnDidDrawRect();
-}
-
-// ThemedWindowDrawing implementation.
-
-- (void)windowDidChangeTheme {
-  [self updateColorsToMatchTheme];
-}
-
-- (void)windowDidChangeActive {
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
deleted file mode 100644
index f4e8081..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm
+++ /dev/null
@@ -1,330 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/strings/string_util.h"
-#include "chrome/app/chrome_command_ids.h"  // IDC_*
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "chrome/grit/generated_resources.h"
-#include "testing/gmock/include/gmock/gmock-matchers.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-#include "third_party/ocmock/gtest_support.h"
-#import "third_party/ocmock/ocmock_extensions.h"
-#import "ui/base/cocoa/touch_bar_forward_declarations.h"
-#import "ui/events/test/cocoa_test_event_utils.h"
-
-using ::testing::Return;
-using ::testing::ReturnArg;
-using ::testing::StrictMock;
-using ::testing::A;
-
-namespace {
-
-NSMenu* MenuFromRightClick(AutocompleteTextFieldEditor* editor) {
-  NSEvent* event = cocoa_test_event_utils::MouseEventAtPoint(
-      NSZeroPoint, NSRightMouseDown, 0);
-  return [editor menuForEvent:event];
-}
-
-// TODO(shess): Very similar to AutocompleteTextFieldTest.  Maybe
-// those can be shared.
-
-class AutocompleteTextFieldEditorTest : public CocoaTest {
- public:
-  void SetUp() override {
-    CocoaTest::SetUp();
-    NSRect frame = NSMakeRect(0, 0, 50, 30);
-    base::scoped_nsobject<AutocompleteTextField> field(
-        [[AutocompleteTextField alloc] initWithFrame:frame]);
-    field_ = field.get();
-    [field_ setStringValue:@"Testing"];
-    [[test_window() contentView] addSubview:field_];
-
-    // Arrange for |field_| to get the right field editor.
-    window_delegate_.reset(
-        [[AutocompleteTextFieldWindowTestDelegate alloc] init]);
-    [test_window() setDelegate:window_delegate_.get()];
-
-    // Get the field editor setup.
-    [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-    editor_ = static_cast<AutocompleteTextFieldEditor*>([field_ currentEditor]);
-
-    EXPECT_TRUE(editor_);
-    EXPECT_TRUE([editor_ isKindOfClass:[AutocompleteTextFieldEditor class]]);
-  }
-
-  AutocompleteTextFieldEditor* editor_;
-  AutocompleteTextField* field_;
-  base::scoped_nsobject<AutocompleteTextFieldWindowTestDelegate>
-      window_delegate_;
-};
-
-// Disabled because it crashes sometimes. http://crbug.com/49522
-// Can't rename DISABLED_ because the TEST_VIEW macro prepends.
-//     http://crbug.com/53621
-#if 0
-TEST_VIEW(AutocompleteTextFieldEditorTest, field_);
-#endif
-
-// Test that control characters are stripped from insertions.
-TEST_F(AutocompleteTextFieldEditorTest, InsertStripsControlChars) {
-  // Sets a string in the field.
-  NSString* test_string = @"astring";
-  [field_ setStringValue:test_string];
-  [editor_ selectAll:nil];
-
-  [editor_ insertText:@"t"];
-  EXPECT_NSEQ(@"t", [field_ stringValue]);
-
-  [editor_ insertText:@"h"];
-  EXPECT_NSEQ(@"th", [field_ stringValue]);
-
-  // TAB doesn't get inserted.
-  [editor_ insertText:[NSString stringWithFormat:@"%c", 7]];
-  EXPECT_NSEQ(@"th", [field_ stringValue]);
-
-  // Newline doesn't get inserted.
-  [editor_ insertText:[NSString stringWithFormat:@"%c", 12]];
-  EXPECT_NSEQ(@"th", [field_ stringValue]);
-
-  // Multi-character strings get through.
-  [editor_ insertText:[NSString stringWithFormat:@"i%cs%c", 8, 127]];
-  EXPECT_NSEQ(@"this", [field_ stringValue]);
-
-  // Attempting to insert newline when everything is selected clears
-  // the field.
-  [editor_ selectAll:nil];
-  [editor_ insertText:[NSString stringWithFormat:@"%c", 12]];
-  EXPECT_NSEQ(@"", [field_ stringValue]);
-}
-
-// Test that |delegate| can provide page action menus.
-TEST_F(AutocompleteTextFieldEditorTest, PageActionMenus) {
-  // The event just needs to be something the mock can recognize.
-  NSEvent* event = cocoa_test_event_utils::MouseEventAtPoint(NSZeroPoint,
-                                                             NSRightMouseDown,
-                                                             0);
-
-  // Trivial menu which we can recognize and which doesn't look like
-  // the default editor context menu.
-  base::scoped_nsobject<id> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
-  [menu addItemWithTitle:@"Go Fish"
-                  action:@selector(goFish:)
-           keyEquivalent:@""];
-
-  // So that we don't have to mock the observer.
-  [editor_ setEditable:NO];
-
-  // The delegate's intercept point gets called, and results are
-  // propagated back.
-  {
-    id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]];
-    [[[delegate stub] andReturnBool:YES]
-      isKindOfClass:[AutocompleteTextField class]];
-    [[[delegate expect] andReturn:menu.get()] decorationMenuForEvent:event];
-    [[[delegate expect] andReturn:nil] undoManagerForTextView:editor_];
-    [editor_ setDelegate:delegate];
-    NSMenu* contextMenu = [editor_ menuForEvent:event];
-    EXPECT_OCMOCK_VERIFY(delegate);
-    [editor_ setDelegate:nil];
-
-    EXPECT_EQ(contextMenu, menu.get());
-  }
-
-  // If the delegate does not return any menu, the default menu is
-  // returned.
-  {
-    id delegate = [OCMockObject mockForClass:[AutocompleteTextField class]];
-    [[[delegate stub] andReturnBool:YES]
-      isKindOfClass:[AutocompleteTextField class]];
-    [[[delegate expect] andReturn:nil] decorationMenuForEvent:event];
-    [[[delegate expect] andReturn:nil] undoManagerForTextView:editor_];
-    [editor_ setDelegate:delegate];
-    NSMenu* contextMenu = [editor_ menuForEvent:event];
-    EXPECT_OCMOCK_VERIFY(delegate);
-    [editor_ setDelegate:nil];
-
-    EXPECT_NE(contextMenu, menu.get());
-    NSArray* items = [contextMenu itemArray];
-    ASSERT_GT([items count], 0U);
-    EXPECT_EQ(@selector(cut:), [[items objectAtIndex:0] action])
-        << "action is: " << sel_getName([[items objectAtIndex:0] action]);
-  }
-}
-
-// Base class for testing AutocompleteTextFieldObserver messages.
-class AutocompleteTextFieldEditorObserverTest
-    : public AutocompleteTextFieldEditorTest {
- public:
-  virtual void SetUp() {
-    AutocompleteTextFieldEditorTest::SetUp();
-    [field_ setObserver:&field_observer_];
-  }
-
-  virtual void TearDown() {
-    // Clear the observer so that we don't show output for
-    // uninteresting messages to the mock (for instance, if |field_| has
-    // focus at the end of the test).
-    [field_ setObserver:NULL];
-
-    AutocompleteTextFieldEditorTest::TearDown();
-  }
-
-  StrictMock<MockAutocompleteTextFieldObserver> field_observer_;
-};
-
-// Test that the field editor is linked in correctly.
-TEST_F(AutocompleteTextFieldEditorTest, FirstResponder) {
-  EXPECT_EQ(editor_, [field_ currentEditor]);
-  EXPECT_TRUE([editor_ isDescendantOf:field_]);
-  EXPECT_EQ([editor_ delegate], field_);
-  EXPECT_EQ([editor_ observer], [field_ observer]);
-}
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(AutocompleteTextFieldEditorTest, Display) {
-  [field_ display];
-  [editor_ display];
-}
-
-// Tests that the Touch Bar is nothing.
-TEST_F(AutocompleteTextFieldEditorTest, TouchBarTest) {
-  if (@available(macOS 10.12.2, *)) {
-    NSTouchBar* touch_bar = [field_ performSelector:@selector(touchBar)];
-    EXPECT_FALSE(touch_bar);
-  }
-}
-
-// Test that -paste: is correctly delegated to the observer.
-TEST_F(AutocompleteTextFieldEditorObserverTest, Paste) {
-  EXPECT_CALL(field_observer_, OnPaste());
-  [editor_ paste:nil];
-}
-
-// Test that -copy: is correctly delegated to the observer.
-TEST_F(AutocompleteTextFieldEditorObserverTest, Copy) {
-  EXPECT_CALL(field_observer_, CanCopy())
-      .WillOnce(Return(true));
-  EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>()))
-      .Times(1);
-  [editor_ copy:nil];
-}
-
-// Test that -cut: is correctly delegated to the observer and clears
-// the text field.
-TEST_F(AutocompleteTextFieldEditorObserverTest, Cut) {
-  // Sets a string in the field.
-  NSString* test_string = @"astring";
-  EXPECT_CALL(field_observer_, OnDidBeginEditing());
-  EXPECT_CALL(field_observer_, OnBeforeChange());
-  EXPECT_CALL(field_observer_, OnDidChange());
-  EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
-      .WillRepeatedly(ReturnArg<0>());
-  [editor_ setString:test_string];
-  [editor_ selectAll:nil];
-
-  // Calls cut.
-  EXPECT_CALL(field_observer_, CanCopy())
-      .WillOnce(Return(true));
-  EXPECT_CALL(field_observer_, CopyToPasteboard(A<NSPasteboard*>()))
-      .Times(1);
-  [editor_ cut:nil];
-
-  // Check if the field is cleared.
-  ASSERT_EQ([[editor_ textStorage] length], 0U);
-}
-
-// Test that -pasteAndGo: is correctly delegated to the observer.
-TEST_F(AutocompleteTextFieldEditorObserverTest, PasteAndGo) {
-  EXPECT_CALL(field_observer_, OnPasteAndGo());
-  [editor_ pasteAndGo:nil];
-}
-
-// Test that the menu is constructed correctly.
-TEST_F(AutocompleteTextFieldEditorObserverTest, Menu) {
-  EXPECT_CALL(field_observer_, CanPasteAndGo()).WillOnce(Return(true));
-  EXPECT_CALL(field_observer_, GetPasteActionStringId()).
-      WillOnce(Return(IDS_PASTE_AND_GO));
-
-  NSMenu* menu = MenuFromRightClick(editor_);
-  NSArray* items = [menu itemArray];
-  ASSERT_EQ([items count], 6U);
-  // TODO(shess): Check the titles, too?
-  NSUInteger i = 0;  // Use an index to make future changes easier.
-  EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
-  EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
-  EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
-  NSMenuItem* pasteAndGo = [items objectAtIndex:i++];
-  EXPECT_EQ([pasteAndGo action], @selector(pasteAndGo:));
-  EXPECT_TRUE([pasteAndGo isEnabled]);
-  EXPECT_TRUE([[items objectAtIndex:i++] isSeparatorItem]);
-  EXPECT_EQ([[items objectAtIndex:i] tag], IDC_EDIT_SEARCH_ENGINES);
-  EXPECT_EQ([[items objectAtIndex:i++] action], @selector(commandDispatch:));
-}
-
-// Test that the menu is constructed correctly when field isn't
-// editable.
-TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoMenuNotEditable) {
-  [field_ setEditable:NO];
-  [editor_ setEditable:NO];
-
-  // Never call this when not editable.
-  EXPECT_CALL(field_observer_, GetPasteActionStringId()).Times(0);
-
-  NSMenu* menu = MenuFromRightClick(editor_);
-  NSArray* items = [menu itemArray];
-  ASSERT_EQ([items count], 3U);
-  // TODO(shess): Check the titles, too?
-  NSUInteger i = 0;  // Use an index to make future changes easier.
-  EXPECT_EQ([[items objectAtIndex:i++] action], @selector(cut:));
-  EXPECT_EQ([[items objectAtIndex:i++] action], @selector(copy:));
-  EXPECT_EQ([[items objectAtIndex:i++] action], @selector(paste:));
-}
-
-// Test that the menu validation works as expected when CanPasteAndGo().
-TEST_F(AutocompleteTextFieldEditorObserverTest, CanPasteAndGoValidate) {
-  EXPECT_CALL(field_observer_, GetPasteActionStringId())
-      .WillOnce(Return(IDS_PASTE_AND_GO));
-  EXPECT_CALL(field_observer_, CanPasteAndGo()).WillOnce(Return(true));
-
-  NSMenu* menu = MenuFromRightClick(editor_);
-  NSArray* items = [menu itemArray];
-  ASSERT_EQ([items count], 6U);
-  for (NSUInteger i = 0; i < [items count]; ++i) {
-    NSMenuItem* item = [items objectAtIndex:i];
-    if ([item action] == @selector(pasteAndGo:)) {
-      EXPECT_TRUE([item isEnabled]);
-      EXPECT_TRUE([editor_ validateMenuItem:item]);
-      break;
-    }
-  }
-}
-
-// Test that the GetPasteActionStringId() is not called when !CanPasteAndGo().
-TEST_F(AutocompleteTextFieldEditorObserverTest, CannotPasteAndGoValidate) {
-  EXPECT_CALL(field_observer_, GetPasteActionStringId()).Times(0);
-  EXPECT_CALL(field_observer_, CanPasteAndGo()).WillOnce(Return(false));
-
-  NSMenu* menu = MenuFromRightClick(editor_);
-  NSArray* items = [menu itemArray];
-  ASSERT_EQ([items count], 6U);
-  for (NSUInteger i = 0; i < [items count]; ++i) {
-    NSMenuItem* item = [items objectAtIndex:i];
-    if ([item action] == @selector(pasteAndGo:)) {
-      EXPECT_FALSE([item isEnabled]);
-      EXPECT_FALSE([editor_ validateMenuItem:item]);
-      break;
-    }
-  }
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
deleted file mode 100644
index 6ad7b0b7..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
+++ /dev/null
@@ -1,980 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <ApplicationServices/ApplicationServices.h>
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#include "ui/base/cocoa/cocoa_base_utils.h"
-
-using ::testing::A;
-using ::testing::InSequence;
-using ::testing::Return;
-using ::testing::ReturnArg;
-using ::testing::StrictMock;
-using ::testing::_;
-
-namespace {
-
-class MockDecoration : public LocationBarDecoration {
- public:
-  virtual CGFloat GetWidthForSpace(CGFloat width) { return 20.0; }
-
-  virtual void DrawInFrame(NSRect frame, NSView* control_view) { ; }
-  MOCK_METHOD0(AcceptsMousePress, AcceptsPress());
-  MOCK_METHOD2(OnMousePressed, bool(NSRect frame, NSPoint location));
-  MOCK_METHOD0(GetMenu, NSMenu*());
-};
-
-// Mock up an incrementing event number.
-NSUInteger eventNumber = 0;
-
-// Create an event of the indicated |type| at |point| within |view|.
-// TODO(shess): Would be nice to have a MockApplication which provided
-// nifty accessors to create these things and inject them.  It could
-// even provide functions for "Click and drag mouse from point A to
-// point B".
-NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type,
-               const NSUInteger clickCount) {
-  NSWindow* window([view window]);
-  const NSPoint locationInWindow([view convertPoint:point toView:nil]);
-  const NSPoint location =
-      ui::ConvertPointFromWindowToScreen(window, locationInWindow);
-  return [NSEvent mouseEventWithType:type
-                            location:location
-                       modifierFlags:0
-                           timestamp:0
-                        windowNumber:[window windowNumber]
-                             context:nil
-                         eventNumber:eventNumber++
-                          clickCount:clickCount
-                            pressure:0.0];
-}
-NSEvent* Event(NSView* view, const NSPoint point, const NSEventType type) {
-  return Event(view, point, type, 1);
-}
-
-// Width of the field so that we don't have to ask |field_| for it all
-// the time.
-static const CGFloat kWidth(300.0);
-
-class AutocompleteTextFieldTest : public CocoaTest {
- public:
-  AutocompleteTextFieldTest() {
-    // Make sure this is wide enough to play games with the cell
-    // decorations.
-    NSRect frame = NSMakeRect(0, 0, kWidth, 30);
-    base::scoped_nsobject<AutocompleteTextField> field(
-        [[AutocompleteTextField alloc] initWithFrame:frame]);
-    field_ = field.get();
-    [field_ setStringValue:@"Test test"];
-    [[test_window() contentView] addSubview:field_];
-
-    AutocompleteTextFieldCell* cell = [field_ cell];
-    [cell clearDecorations];
-
-    mock_leading_decoration_.SetVisible(false);
-    [cell addLeadingDecoration:&mock_leading_decoration_];
-
-    mock_trailing_decoration_.SetVisible(false);
-    [cell addTrailingDecoration:&mock_trailing_decoration_];
-
-    window_delegate_.reset(
-        [[AutocompleteTextFieldWindowTestDelegate alloc] init]);
-    [test_window() setDelegate:window_delegate_.get()];
-  }
-
-  NSEvent* KeyDownEventWithFlags(NSUInteger flags) {
-    return [NSEvent keyEventWithType:NSKeyDown
-                            location:NSZeroPoint
-                       modifierFlags:flags
-                           timestamp:0.0
-                        windowNumber:[test_window() windowNumber]
-                             context:nil
-                          characters:@"a"
-         charactersIgnoringModifiers:@"a"
-                           isARepeat:NO
-                             keyCode:'a'];
-  }
-
-  // Helper to return the field-editor frame being used w/in |field_|.
-  NSRect EditorFrame() {
-    EXPECT_TRUE([field_ currentEditor]);
-    EXPECT_EQ([[field_ subviews] count], 1U);
-    if ([[field_ subviews] count] > 0) {
-      return [[[field_ subviews] objectAtIndex:0] frame];
-    } else {
-      // Return something which won't work so the caller can soldier
-      // on.
-      return NSZeroRect;
-    }
-  }
-
-  AutocompleteTextFieldEditor* FieldEditor() {
-    return base::mac::ObjCCastStrict<AutocompleteTextFieldEditor>(
-        [field_ currentEditor]);
-  }
-
-  AutocompleteTextField* field_;
-  MockDecoration mock_leading_decoration_;
-  MockDecoration mock_trailing_decoration_;
-  base::scoped_nsobject<AutocompleteTextFieldWindowTestDelegate>
-      window_delegate_;
-};
-
-TEST_VIEW(AutocompleteTextFieldTest, field_);
-
-// Base class for testing AutocompleteTextFieldObserver messages.
-class AutocompleteTextFieldObserverTest : public AutocompleteTextFieldTest {
- public:
-  virtual void SetUp() {
-    AutocompleteTextFieldTest::SetUp();
-    [field_ setObserver:&field_observer_];
-  }
-
-  virtual void TearDown() {
-    // Clear the observer so that we don't show output for
-    // uninteresting messages to the mock (for instance, if |field_| has
-    // focus at the end of the test).
-    [field_ setObserver:NULL];
-
-    AutocompleteTextFieldTest::TearDown();
-  }
-
-  // Returns the center point of the decoration.
-  NSPoint ClickLocationForDecoration(LocationBarDecoration* decoration) {
-    AutocompleteTextFieldCell* cell = [field_ cell];
-    NSRect decoration_rect =
-        [cell frameForDecoration:decoration inFrame:[field_ bounds]];
-    EXPECT_FALSE(NSIsEmptyRect(decoration_rect));
-    return NSMakePoint(NSMidX(decoration_rect), NSMidY(decoration_rect));
-  }
-
-  void SendMouseClickToDecoration(LocationBarDecoration* decoration) {
-    NSPoint point = ClickLocationForDecoration(decoration);
-    NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
-    NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
-
-    // Can't just use -sendEvent:, since that doesn't populate -currentEvent.
-    [NSApp postEvent:downEvent atStart:YES];
-    [NSApp postEvent:upEvent atStart:NO];
-
-    NSEvent* next_event = [NSApp nextEventMatchingMask:NSAnyEventMask
-                                             untilDate:nil
-                                                inMode:NSDefaultRunLoopMode
-                                               dequeue:YES];
-    [NSApp sendEvent:next_event];
-  }
-
-  StrictMock<MockAutocompleteTextFieldObserver> field_observer_;
-};
-
-// Test that we have the right cell class.
-TEST_F(AutocompleteTextFieldTest, CellClass) {
-  EXPECT_TRUE([[field_ cell] isKindOfClass:[AutocompleteTextFieldCell class]]);
-}
-
-// Test that becoming first responder sets things up correctly.
-TEST_F(AutocompleteTextFieldTest, FirstResponder) {
-  EXPECT_EQ(nil, [field_ currentEditor]);
-  EXPECT_EQ([[field_ subviews] count], 0U);
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  EXPECT_FALSE(nil == [field_ currentEditor]);
-  EXPECT_EQ([[field_ subviews] count], 1U);
-  EXPECT_TRUE([[field_ currentEditor] isDescendantOf:field_]);
-
-  // Check that the window delegate is providing the right editor.
-  Class c = [AutocompleteTextFieldEditor class];
-  EXPECT_TRUE([[field_ currentEditor] isKindOfClass:c]);
-}
-
-TEST_F(AutocompleteTextFieldTest, AvailableDecorationWidth) {
-  // A fudge factor to account for how much space the border takes up.
-  // The test shouldn't be too dependent on the field's internals, but
-  // it also shouldn't let deranged cases fall through the cracks
-  // (like nothing available with no text, or everything available
-  // with some text).
-  const CGFloat kBorderWidth = 20.0;
-
-  // With no contents, almost the entire width is available for
-  // decorations.
-  [field_ setStringValue:@""];
-  CGFloat availableWidth = [field_ availableDecorationWidth];
-  EXPECT_LE(availableWidth, kWidth);
-  EXPECT_GT(availableWidth, kWidth - kBorderWidth);
-
-  // With minor contents, most of the remaining width is available for
-  // decorations.
-  NSDictionary* attributes =
-      [NSDictionary dictionaryWithObject:[field_ font]
-                                  forKey:NSFontAttributeName];
-  NSString* string = @"Hello world";
-  const NSSize size([string sizeWithAttributes:attributes]);
-  [field_ setStringValue:string];
-  availableWidth = [field_ availableDecorationWidth];
-  EXPECT_LE(availableWidth, kWidth - size.width);
-  EXPECT_GT(availableWidth, kWidth - size.width - kBorderWidth);
-
-  // With huge contents, nothing at all is left for decorations.
-  string = @"A long string which is surely wider than field_ can hold.";
-  [field_ setStringValue:string];
-  availableWidth = [field_ availableDecorationWidth];
-  EXPECT_LT(availableWidth, 0.0);
-}
-
-// Test drawing, mostly to ensure nothing leaks or crashes.
-TEST_F(AutocompleteTextFieldTest, Display) {
-  [field_ display];
-
-  // Test focussed drawing.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  [field_ display];
-}
-
-TEST_F(AutocompleteTextFieldObserverTest, FlagsChanged) {
-  InSequence dummy;  // Call mock in exactly the order specified.
-
-  // Test without Control key down, but some other modifier down.
-  EXPECT_CALL(field_observer_, OnControlKeyChanged(false));
-  [field_ flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)];
-
-  // Test with Control key down.
-  EXPECT_CALL(field_observer_, OnControlKeyChanged(true));
-  [field_ flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)];
-}
-
-// This test is here rather than in the editor's tests because the
-// field catches -flagsChanged: because it's on the responder chain,
-// the field editor doesn't implement it.
-TEST_F(AutocompleteTextFieldObserverTest, FieldEditorFlagsChanged) {
-  // Many of these methods try to change the selection.
-  EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
-      .WillRepeatedly(ReturnArg<0>());
-
-  InSequence dummy;  // Call mock in exactly the order specified.
-  EXPECT_CALL(field_observer_, OnSetFocus(false));
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  NSResponder* firstResponder = [[field_ window] firstResponder];
-  EXPECT_EQ(firstResponder, [field_ currentEditor]);
-
-  // Test without Control key down, but some other modifier down.
-  EXPECT_CALL(field_observer_, OnControlKeyChanged(false));
-  [firstResponder flagsChanged:KeyDownEventWithFlags(NSShiftKeyMask)];
-
-  // Test with Control key down.
-  EXPECT_CALL(field_observer_, OnControlKeyChanged(true));
-  [firstResponder flagsChanged:KeyDownEventWithFlags(NSControlKeyMask)];
-}
-
-// Frame size changes are propagated to |observer_|.
-TEST_F(AutocompleteTextFieldObserverTest, FrameChanged) {
-  EXPECT_CALL(field_observer_, OnFrameChanged());
-  NSRect frame = [field_ frame];
-  frame.size.width += 10.0;
-  [field_ setFrame:frame];
-}
-
-// Test that the field editor gets the same bounds when focus is
-// delivered by the standard focusing machinery, or by
-// -resetFieldEditorFrameIfNeeded.
-TEST_F(AutocompleteTextFieldTest, ResetFieldEditorBase) {
-  // Capture the editor frame resulting from the standard focus
-  // machinery.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  const NSRect baseEditorFrame = EditorFrame();
-
-  // A decoration should result in a strictly smaller editor frame.
-  mock_leading_decoration_.SetVisible(true);
-  [field_ resetFieldEditorFrameIfNeeded];
-  EXPECT_NSNE(baseEditorFrame, EditorFrame());
-  EXPECT_TRUE(NSContainsRect(baseEditorFrame, EditorFrame()));
-
-  // Removing the decoration and using -resetFieldEditorFrameIfNeeded
-  // should result in the same frame as the standard focus machinery.
-  mock_leading_decoration_.SetVisible(false);
-  [field_ resetFieldEditorFrameIfNeeded];
-  EXPECT_NSEQ(baseEditorFrame, EditorFrame());
-}
-
-// Test that the field editor gets the same bounds when focus is
-// delivered by the standard focusing machinery, or by
-// -resetFieldEditorFrameIfNeeded, this time with a decoration
-// pre-loaded.
-TEST_F(AutocompleteTextFieldTest, ResetFieldEditorWithDecoration) {
-  AutocompleteTextFieldCell* cell = [field_ cell];
-
-  // Make sure decoration isn't already visible, then make it visible.
-  EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_
-                                             inFrame:[field_ bounds]]));
-  mock_leading_decoration_.SetVisible(true);
-  EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_
-                                              inFrame:[field_ bounds]]));
-
-  // Capture the editor frame resulting from the standard focus
-  // machinery.
-
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  const NSRect baseEditorFrame = EditorFrame();
-
-  // When the decoration is not visible the frame should be strictly larger.
-  mock_leading_decoration_.SetVisible(false);
-  EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_
-                                             inFrame:[field_ bounds]]));
-  [field_ resetFieldEditorFrameIfNeeded];
-  EXPECT_NSNE(baseEditorFrame, EditorFrame());
-  EXPECT_TRUE(NSContainsRect(EditorFrame(), baseEditorFrame));
-
-  // When the decoration is visible, -resetFieldEditorFrameIfNeeded
-  // should result in the same frame as the standard focus machinery.
-  mock_leading_decoration_.SetVisible(true);
-  EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_
-                                              inFrame:[field_ bounds]]));
-
-  [field_ resetFieldEditorFrameIfNeeded];
-  EXPECT_NSEQ(baseEditorFrame, EditorFrame());
-}
-
-// Test that resetting the field editor bounds does not cause untoward
-// messages to the field's observer.
-TEST_F(AutocompleteTextFieldObserverTest, ResetFieldEditorContinuesEditing) {
-  // Many of these methods try to change the selection.
-  EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
-      .WillRepeatedly(ReturnArg<0>());
-
-  EXPECT_CALL(field_observer_, OnSetFocus(false));
-  // Becoming first responder doesn't begin editing.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  const NSRect baseEditorFrame = EditorFrame();
-  NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
-  EXPECT_TRUE(nil != editor);
-
-  // This should begin editing and indicate a change.
-  EXPECT_CALL(field_observer_, OnDidBeginEditing());
-  EXPECT_CALL(field_observer_, OnBeforeChange());
-  EXPECT_CALL(field_observer_, OnDidChange());
-  [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
-  [editor didChangeText];
-
-  // No messages to |field_observer_| when the frame actually changes.
-  mock_leading_decoration_.SetVisible(true);
-  [field_ resetFieldEditorFrameIfNeeded];
-  EXPECT_NSNE(baseEditorFrame, EditorFrame());
-}
-
-// Clicking in a right-hand decoration which does not handle the mouse
-// puts the caret rightmost.
-TEST_F(AutocompleteTextFieldTest, ClickRightDecorationPutsCaretRightmost) {
-  // Decoration does not handle the mouse event, so the cell should
-  // process it.  Called at least once.
-  EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress())
-      .WillOnce(Return(AcceptsPress::NEVER))
-      .WillRepeatedly(Return(AcceptsPress::NEVER));
-
-  // Set the decoration before becoming responder.
-  EXPECT_FALSE([field_ currentEditor]);
-  mock_trailing_decoration_.SetVisible(true);
-
-  // Make first responder should select all.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  EXPECT_TRUE([field_ currentEditor]);
-  const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
-  EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
-
-  // Generate a click on the decoration.
-  AutocompleteTextFieldCell* cell = [field_ cell];
-  const NSRect bounds = [field_ bounds];
-  const NSRect iconFrame =
-      [cell frameForDecoration:&mock_trailing_decoration_ inFrame:bounds];
-  const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
-  NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
-  NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
-  [NSApp postEvent:upEvent atStart:YES];
-  [field_ mouseDown:downEvent];
-
-  // Selection should be a right-hand-side caret.
-  EXPECT_TRUE(NSEqualRanges(NSMakeRange([[field_ stringValue] length], 0),
-                            [[field_ currentEditor] selectedRange]));
-}
-
-// Clicking in a left-side decoration which doesn't handle the event
-// puts the selection in the leftmost position.
-TEST_F(AutocompleteTextFieldTest, ClickLeftDecorationPutsCaretLeftmost) {
-  // Decoration does not handle the mouse event, so the cell should
-  // process it.  Called at least once.
-  EXPECT_CALL(mock_leading_decoration_, AcceptsMousePress())
-      .WillOnce(Return(AcceptsPress::NEVER))
-      .WillRepeatedly(Return(AcceptsPress::NEVER));
-
-  // Set the decoration before becoming responder.
-  EXPECT_FALSE([field_ currentEditor]);
-  mock_leading_decoration_.SetVisible(true);
-
-  // Make first responder should select all.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  EXPECT_TRUE([field_ currentEditor]);
-  const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
-  EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
-
-  // Generate a click on the decoration.
-  AutocompleteTextFieldCell* cell = [field_ cell];
-  const NSRect bounds = [field_ bounds];
-  const NSRect iconFrame =
-      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
-  const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
-  NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
-  NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
-  [NSApp postEvent:upEvent atStart:YES];
-  [field_ mouseDown:downEvent];
-
-  // Selection should be a left-hand-side caret.
-  EXPECT_TRUE(NSEqualRanges(NSMakeRange(0, 0),
-                            [[field_ currentEditor] selectedRange]));
-}
-
-// Clicks not in the text area or the cell's decorations fall through
-// to the editor.
-TEST_F(AutocompleteTextFieldTest, ClickBorderSelectsAll) {
-  // Can't rely on the window machinery to make us first responder,
-  // here.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  EXPECT_TRUE([field_ currentEditor]);
-
-  const NSPoint point(NSMakePoint(20.0, 1.0));
-  NSEvent* downEvent(Event(field_, point, NSLeftMouseDown));
-  NSEvent* upEvent(Event(field_, point, NSLeftMouseUp));
-  [NSApp postEvent:upEvent atStart:YES];
-  [field_ mouseDown:downEvent];
-
-  // Clicking in the narrow border area around a Cocoa NSTextField
-  // does a select-all.  Regardless of whether this is a good call, it
-  // works as a test that things get passed down to the editor.
-  const NSRange selectedRange([[field_ currentEditor] selectedRange]);
-  EXPECT_EQ(selectedRange.location, 0U);
-  EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
-}
-
-// Single-click with no drag should setup a field editor and
-// select all.
-TEST_F(AutocompleteTextFieldTest, ClickSelectsAll) {
-  EXPECT_FALSE([field_ currentEditor]);
-
-  const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds]));
-  NSEvent* downEvent(Event(field_, point, NSLeftMouseDown));
-  NSEvent* upEvent(Event(field_, point, NSLeftMouseUp));
-  [NSApp postEvent:upEvent atStart:YES];
-  [field_ mouseDown:downEvent];
-  EXPECT_TRUE([field_ currentEditor]);
-  const NSRange selectedRange([[field_ currentEditor] selectedRange]);
-  EXPECT_EQ(selectedRange.location, 0U);
-  EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
-}
-
-// Click-drag selects text, not select all.
-TEST_F(AutocompleteTextFieldTest, ClickDragSelectsText) {
-  EXPECT_FALSE([field_ currentEditor]);
-
-  NSEvent* downEvent(Event(field_, NSMakePoint(20.0, 5.0), NSLeftMouseDown));
-  NSEvent* upEvent(Event(field_, NSMakePoint(0.0, 5.0), NSLeftMouseUp));
-  [NSApp postEvent:upEvent atStart:YES];
-  [field_ mouseDown:downEvent];
-  EXPECT_TRUE([field_ currentEditor]);
-
-  // Expect this to have selected a prefix of the content.  Mostly
-  // just don't want the select-all behavior.
-  const NSRange selectedRange([[field_ currentEditor] selectedRange]);
-  EXPECT_EQ(selectedRange.location, 0U);
-  EXPECT_LT(selectedRange.length, [[field_ stringValue] length]);
-}
-
-// TODO(shess): Test that click/pause/click allows cursor placement.
-// In this case the first click goes to the field, but the second
-// click goes to the field editor, so the current testing pattern
-// can't work.  What really needs to happen is to push through the
-// NSWindow event machinery so that we can say "two independent clicks
-// at the same location have the right effect".  Once that is done, it
-// might make sense to revise the other tests to use the same
-// machinery.
-
-// Double-click selects word, not select all.
-TEST_F(AutocompleteTextFieldTest, DoubleClickSelectsWord) {
-  EXPECT_FALSE([field_ currentEditor]);
-
-  const NSPoint point = NSMakePoint(20.0, NSMidY([field_ bounds]));
-  NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1));
-  NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1));
-  NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2));
-  NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2));
-  [NSApp postEvent:upEvent atStart:YES];
-  [field_ mouseDown:downEvent];
-  [NSApp postEvent:upEvent2 atStart:YES];
-  [field_ mouseDown:downEvent2];
-  EXPECT_TRUE([field_ currentEditor]);
-
-  // Selected the first word.
-  const NSRange selectedRange([[field_ currentEditor] selectedRange]);
-  const NSRange spaceRange([[field_ stringValue] rangeOfString:@" "]);
-  EXPECT_GT(spaceRange.location, 0U);
-  EXPECT_LT(spaceRange.length, [[field_ stringValue] length]);
-  EXPECT_EQ(selectedRange.location, 0U);
-  EXPECT_EQ(selectedRange.length, spaceRange.location);
-}
-
-TEST_F(AutocompleteTextFieldTest, TripleClickSelectsAll) {
-  EXPECT_FALSE([field_ currentEditor]);
-
-  const NSPoint point(NSMakePoint(20.0, 5.0));
-  NSEvent* downEvent(Event(field_, point, NSLeftMouseDown, 1));
-  NSEvent* upEvent(Event(field_, point, NSLeftMouseUp, 1));
-  NSEvent* downEvent2(Event(field_, point, NSLeftMouseDown, 2));
-  NSEvent* upEvent2(Event(field_, point, NSLeftMouseUp, 2));
-  NSEvent* downEvent3(Event(field_, point, NSLeftMouseDown, 3));
-  NSEvent* upEvent3(Event(field_, point, NSLeftMouseUp, 3));
-  [NSApp postEvent:upEvent atStart:YES];
-  [field_ mouseDown:downEvent];
-  [NSApp postEvent:upEvent2 atStart:YES];
-  [field_ mouseDown:downEvent2];
-  [NSApp postEvent:upEvent3 atStart:YES];
-  [field_ mouseDown:downEvent3];
-  EXPECT_TRUE([field_ currentEditor]);
-
-  // Selected the first word.
-  const NSRange selectedRange([[field_ currentEditor] selectedRange]);
-  EXPECT_EQ(selectedRange.location, 0U);
-  EXPECT_EQ(selectedRange.length, [[field_ stringValue] length]);
-}
-
-// Clicking a decoration should call decoration's OnMousePressed.
-TEST_F(AutocompleteTextFieldTest, LeftDecorationMouseDown) {
-  // At this point, not focussed.
-  EXPECT_FALSE([field_ currentEditor]);
-
-  mock_leading_decoration_.SetVisible(true);
-  EXPECT_CALL(mock_leading_decoration_, AcceptsMousePress())
-      .WillRepeatedly(Return(AcceptsPress::ALWAYS));
-
-  AutocompleteTextFieldCell* cell = [field_ cell];
-  [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_];
-
-  const NSRect iconFrame = [cell frameForDecoration:&mock_leading_decoration_
-                                            inFrame:[field_ bounds]];
-  const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
-  NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
-  NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
-
-  // Since decorations can be dragged, the mouse-press is sent on
-  // mouse-up.
-  [NSApp postEvent:upEvent atStart:YES];
-
-  EXPECT_CALL(mock_leading_decoration_, OnMousePressed(_, _))
-      .WillOnce(Return(true));
-  [field_ mouseDown:downEvent];
-
-  // Focus the field and test that handled clicks don't affect selection.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  EXPECT_TRUE([field_ currentEditor]);
-  const NSRange allRange = NSMakeRange(0, [[field_ stringValue] length]);
-  EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
-
-  // Generate another click on the decoration.
-  downEvent = Event(field_, location, NSLeftMouseDown, 1);
-  upEvent = Event(field_, location, NSLeftMouseUp, 1);
-  [NSApp postEvent:upEvent atStart:YES];
-  EXPECT_CALL(mock_leading_decoration_, OnMousePressed(_, _))
-      .WillOnce(Return(true));
-  [field_ mouseDown:downEvent];
-
-  // The selection should not have changed.
-  EXPECT_TRUE(NSEqualRanges(allRange, [[field_ currentEditor] selectedRange]));
-
-  // TODO(shess): Test that mouse drags are initiated if the next
-  // event is a drag, or if the mouse-up takes too long to arrive.
-  // IDEA: mock decoration to return a pasteboard which a mock
-  // AutocompleteTextField notes in -dragImage:*.
-}
-
-// Clicking a decoration should call decoration's OnMousePressed.
-TEST_F(AutocompleteTextFieldTest, RightDecorationMouseDown) {
-  // At this point, not focussed.
-  EXPECT_FALSE([field_ currentEditor]);
-
-  mock_trailing_decoration_.SetVisible(true);
-  EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress())
-      .WillRepeatedly(Return(AcceptsPress::ALWAYS));
-
-  AutocompleteTextFieldCell* cell = [field_ cell];
-  [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_];
-
-  const NSRect bounds = [field_ bounds];
-  const NSRect iconFrame =
-      [cell frameForDecoration:&mock_trailing_decoration_ inFrame:bounds];
-  const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
-  NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
-  NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
-
-  // Since decorations can be dragged, the mouse-press is sent on
-  // mouse-up.
-  [NSApp postEvent:upEvent atStart:YES];
-
-  EXPECT_CALL(mock_trailing_decoration_, OnMousePressed(_, _))
-      .WillOnce(Return(true));
-  [field_ mouseDown:downEvent];
-}
-
-// Test that page action menus are properly returned.
-// TODO(shess): Really, this should test that things are forwarded to
-// the cell, and the cell tests should test that the right things are
-// selected.  It's easier to mock the event here, though.  This code's
-// event-mockers might be worth promoting to |cocoa_test_event_utils.h| or
-// |cocoa_test_helper.h|.
-TEST_F(AutocompleteTextFieldTest, DecorationMenu) {
-  AutocompleteTextFieldCell* cell = [field_ cell];
-  const NSRect bounds([field_ bounds]);
-
-  const CGFloat edge = NSHeight(bounds) - 4.0;
-  const NSSize size = NSMakeSize(edge, edge);
-  base::scoped_nsobject<NSImage> image([[NSImage alloc] initWithSize:size]);
-
-  base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
-
-  mock_leading_decoration_.SetVisible(true);
-  mock_trailing_decoration_.SetVisible(true);
-
-  // The item with a menu returns it.
-  NSRect actionFrame =
-      [cell frameForDecoration:&mock_trailing_decoration_ inFrame:bounds];
-  NSPoint location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
-  NSEvent* event = Event(field_, location, NSRightMouseDown, 1);
-
-  // Check that the decoration is called, and the field returns the
-  // menu.
-  EXPECT_CALL(mock_trailing_decoration_, GetMenu())
-      .WillOnce(Return(menu.get()));
-  NSMenu *decorationMenu = [field_ decorationMenuForEvent:event];
-  EXPECT_EQ(decorationMenu, menu);
-
-  // The item without a menu returns nil.
-  EXPECT_CALL(mock_leading_decoration_, GetMenu())
-      .WillOnce(Return(static_cast<NSMenu*>(nil)));
-  actionFrame =
-      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
-  location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
-  event = Event(field_, location, NSRightMouseDown, 1);
-  EXPECT_FALSE([field_ decorationMenuForEvent:event]);
-
-  // Something not in an action returns nil.
-  location = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
-  event = Event(field_, location, NSRightMouseDown, 1);
-  EXPECT_FALSE([field_ decorationMenuForEvent:event]);
-}
-
-// Verify that -setAttributedStringValue: works as expected when
-// focussed or when not focussed.  Our code mostly depends on about
-// whether -stringValue works right.
-TEST_F(AutocompleteTextFieldTest, SetAttributedStringBaseline) {
-  EXPECT_EQ(nil, [field_ currentEditor]);
-
-  // So that we can set rich text.
-  [field_ setAllowsEditingTextAttributes:YES];
-
-  // Set an attribute different from the field's default so we can
-  // tell we got the same string out as we put in.
-  NSFont* font = [NSFont fontWithDescriptor:[[field_ font] fontDescriptor]
-                                       size:[[field_ font] pointSize] + 2];
-  NSDictionary* attributes =
-      [NSDictionary dictionaryWithObject:font
-                                  forKey:NSFontAttributeName];
-  NSString* const kString = @"This is a test";
-  base::scoped_nsobject<NSAttributedString> attributedString(
-      [[NSAttributedString alloc] initWithString:kString
-                                      attributes:attributes]);
-
-  // Check that what we get back looks like what we put in.
-  EXPECT_NSNE(kString, [field_ stringValue]);
-  [field_ setAttributedStringValue:attributedString];
-  EXPECT_TRUE([[field_ attributedStringValue]
-                isEqualToAttributedString:attributedString]);
-  EXPECT_NSEQ(kString, [field_ stringValue]);
-
-  // Try that again with focus.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-
-  EXPECT_TRUE([field_ currentEditor]);
-
-  // Check that what we get back looks like what we put in.
-  [field_ setStringValue:@""];
-  EXPECT_NSNE(kString, [field_ stringValue]);
-  [field_ setAttributedStringValue:attributedString];
-  EXPECT_TRUE([[field_ attributedStringValue]
-                isEqualToAttributedString:attributedString]);
-  EXPECT_NSEQ(kString, [field_ stringValue]);
-}
-
-// -setAttributedStringValue: shouldn't reset the undo state if things
-// are being editted.
-TEST_F(AutocompleteTextFieldTest, SetAttributedStringUndo) {
-  NSColor* redColor = [NSColor redColor];
-  NSDictionary* attributes =
-      [NSDictionary dictionaryWithObject:redColor
-                                  forKey:NSForegroundColorAttributeName];
-  NSString* const kString = @"This is a test";
-  base::scoped_nsobject<NSAttributedString> attributedString(
-      [[NSAttributedString alloc] initWithString:kString
-                                      attributes:attributes]);
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  EXPECT_TRUE([field_ currentEditor]);
-  NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
-  NSUndoManager* undoManager = [editor undoManager];
-  EXPECT_TRUE(undoManager);
-
-  // Nothing to undo, yet.
-  EXPECT_FALSE([undoManager canUndo]);
-
-  // Starting an editing action creates an undoable item.
-  [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
-  [editor didChangeText];
-  EXPECT_TRUE([undoManager canUndo]);
-
-  // -setStringValue: resets the editor's undo chain.
-  [field_ setStringValue:kString];
-  EXPECT_FALSE([undoManager canUndo]);
-
-  // Verify that -setAttributedStringValue: does not reset the
-  // editor's undo chain.
-  [field_ setStringValue:@""];
-  [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
-  [editor didChangeText];
-  EXPECT_TRUE([undoManager canUndo]);
-  [field_ setAttributedStringValue:attributedString];
-  EXPECT_TRUE([undoManager canUndo]);
-
-  // Verify that calling -clearUndoChain clears the undo chain.
-  [field_ clearUndoChain];
-  EXPECT_FALSE([undoManager canUndo]);
-}
-
-TEST_F(AutocompleteTextFieldTest, EditorGetsCorrectUndoManager) {
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-
-  NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
-  EXPECT_TRUE(editor);
-  EXPECT_EQ([field_ undoManagerForTextView:editor], [editor undoManager]);
-}
-
-// Verify that hideFocusState correctly hides the focus ring and insertion
-// pointer.
-TEST_F(AutocompleteTextFieldTest, HideFocusState) {
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  [[field_ cell] setShowsFirstResponder:YES];
-
-  EXPECT_TRUE([[field_ cell] showsFirstResponder]);
-  EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]);
-
-  [[field_ cell] setHideFocusState:YES
-                            ofView:field_];
-  EXPECT_FALSE([[field_ cell] showsFirstResponder]);
-  EXPECT_FALSE([FieldEditor() shouldDrawInsertionPoint]);
-
-  [[field_ cell] setHideFocusState:NO
-                            ofView:field_];
-  EXPECT_TRUE([[field_ cell] showsFirstResponder]);
-  EXPECT_TRUE([FieldEditor() shouldDrawInsertionPoint]);
-}
-
-// Verify that the tracking areas are added properly.
-TEST_F(AutocompleteTextFieldTest, UpdateTrackingAreas) {
-  AutocompleteTextFieldCell* cell = [field_ cell];
-
-  mock_leading_decoration_.SetVisible(true);
-  mock_trailing_decoration_.SetVisible(true);
-
-  EXPECT_CALL(mock_leading_decoration_, AcceptsMousePress())
-      .WillOnce(Return(AcceptsPress::ALWAYS))
-      .WillRepeatedly(Return(AcceptsPress::ALWAYS));
-  EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress())
-      .WillOnce(Return(AcceptsPress::NEVER))
-      .WillRepeatedly(Return(AcceptsPress::NEVER));
-  [cell updateMouseTrackingAndToolTipsInRect:[field_ bounds] ofView:field_];
-
-  EXPECT_EQ([cell mouseTrackingDecorations].size(), 1.0);
-
-  [cell clearTrackingArea];
-  EXPECT_TRUE([cell mouseTrackingDecorations].empty());
-
-  EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress())
-      .WillOnce(Return(AcceptsPress::ALWAYS))
-      .WillRepeatedly(Return(AcceptsPress::ALWAYS));
-
-  [cell updateMouseTrackingAndToolTipsInRect:[field_ bounds] ofView:field_];
-  EXPECT_EQ([cell mouseTrackingDecorations].size(), 2.0);
-}
-
-// Verify that clicking a decoration that accepts mouse clicks does not focus
-// the Omnibox.
-TEST_F(AutocompleteTextFieldObserverTest,
-       ClickingDecorationDoesNotFocusOmnibox) {
-  AutocompleteTextFieldCell* cell = [field_ cell];
-
-  // Set up a non-interactive decoration.
-  MockDecoration noninteractive_decoration;
-  noninteractive_decoration.SetVisible(true);
-  EXPECT_CALL(noninteractive_decoration, AcceptsMousePress())
-      .WillRepeatedly(Return(AcceptsPress::NEVER));
-  [cell addLeadingDecoration:&noninteractive_decoration];
-
-  // Set up an interactive decoration.
-  MockDecoration interactive_decoration;
-  EXPECT_CALL(interactive_decoration, AcceptsMousePress())
-      .WillRepeatedly(Return(AcceptsPress::ALWAYS));
-  interactive_decoration.SetVisible(true);
-  [cell addLeadingDecoration:&interactive_decoration];
-  [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_];
-  EXPECT_CALL(interactive_decoration, OnMousePressed(_, _))
-      .WillRepeatedly(testing::Return(true));
-
-  // Ignore incidental calls. The exact frequency of these calls doesn't matter
-  // as they are auxiliary.
-  EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(_))
-      .WillRepeatedly(testing::Return(NSMakeRange(0, 0)));
-  EXPECT_CALL(field_observer_, OnMouseDown(_)).Times(testing::AnyNumber());
-  EXPECT_CALL(field_observer_, OnSetFocus(false)).Times(testing::AnyNumber());
-  EXPECT_CALL(field_observer_, OnKillFocus()).Times(testing::AnyNumber());
-  EXPECT_CALL(field_observer_, OnDidEndEditing()).Times(testing::AnyNumber());
-  EXPECT_CALL(field_observer_, OnBeforeDrawRect()).Times(testing::AnyNumber());
-  EXPECT_CALL(field_observer_, OnDidDrawRect()).Times(testing::AnyNumber());
-
-  // Ensure the field is currently not first responder.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:nil];
-  NSResponder* firstResponder = [[field_ window] firstResponder];
-  EXPECT_FALSE(
-      [base::mac::ObjCCast<NSView>(firstResponder) isDescendantOf:field_]);
-
-  // Clicking an interactive decoration doesn't change the first responder.
-  SendMouseClickToDecoration(&interactive_decoration);
-  EXPECT_NSEQ(firstResponder, [[field_ window] firstResponder]);
-
-  // Clicking a non-interactive decoration focuses the Omnibox.
-  SendMouseClickToDecoration(&noninteractive_decoration);
-  firstResponder = [[field_ window] firstResponder];
-  EXPECT_TRUE(
-      [base::mac::ObjCCast<NSView>(firstResponder) isDescendantOf:field_]);
-
-  // Clicking an interactive decoration doesn't change the first responder.
-  SendMouseClickToDecoration(&interactive_decoration);
-  EXPECT_NSEQ(firstResponder, [[field_ window] firstResponder]);
-}
-
-// Verify the behavior of AcceptsPress::WHEN_ACTIVATED.
-TEST_F(AutocompleteTextFieldObserverTest, ReceivePressOnlyWhenActivated) {
-  AutocompleteTextFieldCell* cell = [field_ cell];
-
-  // Have the mock use AcceptsPress::WHEN_ACTIVATED.
-  MockDecoration decoration;
-  EXPECT_CALL(decoration, AcceptsMousePress())
-      .WillRepeatedly(Return(AcceptsPress::WHEN_ACTIVATED));
-
-  decoration.SetVisible(true);
-  [cell addLeadingDecoration:&decoration];
-  [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_];
-
-  EXPECT_CALL(field_observer_, OnMouseDown(_)).Times(testing::AnyNumber());
-
-  // Expect a call to OnMousePressed(), since the decoration is not active yet.
-  EXPECT_CALL(decoration, OnMousePressed(_, _)).WillOnce(Return(true));
-  SendMouseClickToDecoration(&decoration);
-  decoration.SetActive(true);
-
-  // Click again: should be no additional calls, since the decoration is active.
-  EXPECT_CALL(decoration, OnMousePressed(_, _)).Times(0);
-  SendMouseClickToDecoration(&decoration);
-
-  // Most popups will call SetActive(false) due to a click occurring outside the
-  // bubble. (But there is defensive code that makes this unnecessary). Test
-  // what a popup _should_ do.
-  decoration.SetActive(false);
-  EXPECT_CALL(decoration, OnMousePressed(_, _)).WillOnce(Return(true));
-  SendMouseClickToDecoration(&decoration);
-
-  // And test a misbehaving bubble that forgets to call SetActive(false). It
-  // should still see the second click.
-  decoration.SetActive(true);
-  EXPECT_CALL(decoration, OnMousePressed(_, _)).Times(0);
-  SendMouseClickToDecoration(&decoration);
-  EXPECT_CALL(decoration, OnMousePressed(_, _)).WillOnce(Return(true));
-  SendMouseClickToDecoration(&decoration);
-
-  // Verify that AcceptsPress::ALWAYS receives presses when active.
-  EXPECT_CALL(decoration, AcceptsMousePress())
-      .WillRepeatedly(Return(AcceptsPress::ALWAYS));
-  decoration.SetActive(true);
-  EXPECT_CALL(decoration, OnMousePressed(_, _)).WillOnce(Return(true));
-  SendMouseClickToDecoration(&decoration);
-}
-
-TEST_F(AutocompleteTextFieldObserverTest, SendsEditingMessages) {
-  // Many of these methods try to change the selection.
-  EXPECT_CALL(field_observer_, SelectionRangeForProposedRange(A<NSRange>()))
-      .WillRepeatedly(ReturnArg<0>());
-
-  EXPECT_CALL(field_observer_, OnSetFocus(false));
-  // Becoming first responder doesn't begin editing.
-  [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
-  NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
-  EXPECT_TRUE(nil != editor);
-
-  // This should begin editing and indicate a change.
-  EXPECT_CALL(field_observer_, OnDidBeginEditing());
-  EXPECT_CALL(field_observer_, OnBeforeChange());
-  EXPECT_CALL(field_observer_, OnDidChange());
-  [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
-  [editor didChangeText];
-
-  // Further changes don't send the begin message.
-  EXPECT_CALL(field_observer_, OnBeforeChange());
-  EXPECT_CALL(field_observer_, OnDidChange());
-  [editor shouldChangeTextInRange:NSMakeRange(0, 0) replacementString:@""];
-  [editor didChangeText];
-
-  // -doCommandBySelector: should forward to observer via |field_|.
-  // TODO(shess): Test with a fake arrow-key event?
-  const SEL cmd = @selector(moveDown:);
-  EXPECT_CALL(field_observer_, OnDoCommandBySelector(cmd))
-      .WillOnce(Return(true));
-  [editor doCommandBySelector:cmd];
-
-  // Finished with the changes.
-  EXPECT_CALL(field_observer_, OnKillFocus());
-  EXPECT_CALL(field_observer_, OnDidEndEditing());
-  [test_window() clearPretendKeyWindowAndFirstResponder];
-}
-
-// Test that the resign-key notification is forwarded right, and that
-// the notification is registered and unregistered when the view moves
-// in and out of the window.
-// TODO(shess): Should this test the key window for realz?  That would
-// be really annoying to whoever is running the tests.
-TEST_F(AutocompleteTextFieldObserverTest, ClosePopupOnResignKey) {
-  EXPECT_CALL(field_observer_, ClosePopup());
-  [test_window() resignKeyWindow];
-
-  base::scoped_nsobject<AutocompleteTextField> pin([field_ retain]);
-  [field_ removeFromSuperview];
-  [test_window() resignKeyWindow];
-
-  [[test_window() contentView] addSubview:field_];
-  EXPECT_CALL(field_observer_, ClosePopup());
-  [test_window() resignKeyWindow];
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
deleted file mode 100644
index 88a6f0a..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-@class AutocompleteTextFieldEditor;
-
-// Return the right field editor for AutocompleteTextField instance.
-
-@interface AutocompleteTextFieldWindowTestDelegate :
-    NSObject<NSWindowDelegate> {
-  base::scoped_nsobject<AutocompleteTextFieldEditor> editor_;
-}
-- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject;
-@end
-
-// Allow monitoring calls into AutocompleteTextField's observer.
-// Being in a .h file with an anonymous namespace is strange, but this
-// is here so the mock interface doesn't have to change in multiple
-// places.
-
-// Any method you add here needs a unit test.  You knew that.
-
-class MockAutocompleteTextFieldObserver : public AutocompleteTextFieldObserver {
- public:
-  MockAutocompleteTextFieldObserver();
-  ~MockAutocompleteTextFieldObserver();
-
-  MOCK_METHOD1(SelectionRangeForProposedRange, NSRange(NSRange range));
-  MOCK_METHOD1(OnControlKeyChanged, void(bool pressed));
-  MOCK_METHOD0(CanCopy, bool());
-  MOCK_METHOD0(CreatePasteboardItem, base::scoped_nsobject<NSPasteboardItem>());
-  MOCK_METHOD1(CopyToPasteboard, void(NSPasteboard* pboard));
-  MOCK_METHOD0(OnPaste, void());
-  MOCK_METHOD0(CanPasteAndGo, bool());
-  MOCK_METHOD0(GetPasteActionStringId, int());
-  MOCK_METHOD0(OnPasteAndGo, void());
-  MOCK_METHOD0(OnFrameChanged, void());
-  MOCK_METHOD0(ClosePopup, void());
-  MOCK_METHOD0(OnDidBeginEditing, void());
-  MOCK_METHOD0(OnBeforeChange, void());
-  MOCK_METHOD0(OnDidChange, void());
-  MOCK_METHOD0(OnDidEndEditing, void());
-  MOCK_METHOD0(OnInsertText, void());
-  MOCK_METHOD0(OnBeforeDrawRect, void());
-  MOCK_METHOD0(OnDidDrawRect, void());
-  MOCK_METHOD1(OnDoCommandBySelector, bool(SEL cmd));
-  MOCK_METHOD1(OnSetFocus, void(bool control_down));
-  MOCK_METHOD0(OnKillFocus, void());
-  MOCK_METHOD1(OnMouseDown, void(NSInteger button_number));
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_AUTOCOMPLETE_TEXT_FIELD_UNITTEST_HELPER_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm
deleted file mode 100644
index 38d27935..0000000
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h"
-
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-@implementation AutocompleteTextFieldWindowTestDelegate
-
-- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject {
-  id editor = nil;
-  if ([anObject isKindOfClass:[AutocompleteTextField class]]) {
-    if (editor_ == nil) {
-      editor_.reset([[AutocompleteTextFieldEditor alloc] init]);
-    }
-    EXPECT_TRUE(editor_ != nil);
-
-    // This needs to be called every time, otherwise notifications
-    // aren't sent correctly.
-    [editor_ setFieldEditor:YES];
-    editor = editor_.get();
-  }
-  return editor;
-}
-
-@end
-
-MockAutocompleteTextFieldObserver::MockAutocompleteTextFieldObserver() {}
-
-MockAutocompleteTextFieldObserver::~MockAutocompleteTextFieldObserver() {}
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h
deleted file mode 100644
index 72d46bf..0000000
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h
+++ /dev/null
@@ -1,249 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
-#define CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-@class DecorationMouseTrackingDelegate;
-@class CrTrackingArea;
-
-namespace gfx {
-struct VectorIcon;
-}
-
-namespace test {
-class LocationBarDecorationTestApi;
-}
-
-// Base class for decorations at the left and right of the location
-// bar.  For instance, the location icon.
-
-// |LocationBarDecoration| and subclasses should approximately
-// parallel the classes provided under views/location_bar/.  The term
-// "decoration" is used because "view" has strong connotations in
-// Cocoa, and while these are view-like, they aren't views at all.
-// Decorations are more like Cocoa cells, except implemented in C++ to
-// allow more similarity to the other platform implementations.
-
-// This enum class represents the state of the decoration's interactions
-// with the mouse.
-enum class DecorationMouseState { NONE, HOVER, PRESSED };
-
-// Return values to indicate when subclasses should receive a press event.
-enum class AcceptsPress {
-  NEVER,           // Decoration is not clickable (decorative only).
-  ALWAYS,          // Receives a press whether the button is active or not.
-  WHEN_ACTIVATED,  // Receives a press only if the button was inactive before
-                   // the press began.
-};
-
-class LocationBarDecoration {
- public:
-  LocationBarDecoration();
-  virtual ~LocationBarDecoration();
-
-  // Determines whether the decoration is visible.
-  virtual bool IsVisible() const;
-  virtual void SetVisible(bool visible);
-
-  // Decorations can change their size to fit the available space.
-  // Returns the width the decoration will use in the space allotted,
-  // or |kOmittedWidth| if it should be omitted.
-  virtual CGFloat GetWidthForSpace(CGFloat width);
-
-  // Returns a NSRect derived from |frame| for the background to fill.
-  virtual NSRect GetBackgroundFrame(NSRect frame);
-
-  // Draw the decoration in the frame provided.  The frame will be
-  // generated from an earlier call to |GetWidthForSpace()|.
-  virtual void DrawInFrame(NSRect frame, NSView* control_view);
-
-  // Draw the decoration in the frame provided, possibly including a
-  // background that fills |background_frame|.  The frame will be
-  // generated from an earlier call to |GetWidthForSpace()|, and the
-  // |background_frame| will include the column of pixels exactly
-  // between two decorations.
-  void DrawWithBackgroundInFrame(NSRect frame, NSView* control_view);
-
-  // Returns the tooltip for this decoration, return |nil| for no tooltip.
-  virtual NSString* GetToolTip();
-
-  // Returns the accessibility label for this decoration, return |nil| to use
-  // the result of |GetTooltip()| as a fallback.
-  virtual NSString* GetAccessibilityLabel();
-
-  // Returns whether this decoration is a visual decoration only. Any decoration
-  // that is purely visual must have its state reflected elsewhere to make it
-  // available to screenreader users.
-  virtual bool IsAccessibilityIgnored();
-
-  // Returns a NSRect derived from |frame| to set up the tracking area.
-  virtual NSRect GetTrackingFrame(NSRect frame);
-
-  // Methods to set up and remove the tracking area from the |control_view|.
-  CrTrackingArea* SetupTrackingArea(NSRect frame, NSView* control_view);
-  void RemoveTrackingArea();
-
-  // Decorations which do not accept mouse events are treated like the
-  // field's background for purposes of selecting text.  When such
-  // decorations are adjacent to the text area, they will show the
-  // I-beam cursor.  Decorations which do accept mouse events will get
-  // an arrow cursor when the mouse is over them.
-  virtual AcceptsPress AcceptsMousePress();
-
-  // Returns true if the decoration should display a background if it's
-  // hovered or pressed. The default value is equivalent to the value returned
-  // from AcceptsMousePress().
-  virtual bool HasHoverAndPressEffect();
-
-  // Determine if the item can act as a drag source.
-  virtual bool IsDraggable();
-
-  // The image to drag.
-  virtual NSImage* GetDragImage();
-
-  // Return the place within the decoration's frame where the
-  // |GetDragImage()| comes from.  This is used to make sure the image
-  // appears correctly under the mouse while dragging.  |frame|
-  // matches the frame passed to |DrawInFrame()|.
-  virtual NSRect GetDragImageFrame(NSRect frame);
-
-  // The pasteboard to drag.
-  virtual NSPasteboard* GetDragPasteboard();
-
-  // Called on mouse down. Or, for draggable buttons, on mouse up when a drag
-  // did not occur. Returns |false| to indicate that the press was not processed
-  // and should be handled by the cell.
-  bool HandleMousePressed(NSRect frame, NSPoint location);
-
-  // Hook for subclasses to react to calls to HandleMousePressed(). Not invoked
-  // if the button was already active and AcceptsMousePress() is WHEN_ACTIVATED.
-  virtual bool OnMousePressed(NSRect frame, NSPoint location);
-
-  // Mouse events called on mouse down/up.
-  void OnMouseDown();
-  void OnMouseUp();
-
-  // Called by |tracking_delegate_| when the mouse enters/exits the decoration.
-  void OnMouseEntered();
-  void OnMouseExited();
-
-  // Sets the active state of the decoration. If the state has changed, call
-  // UpdateDecorationState().
-  void SetActive(bool active);
-
-  // Called to get the right-click menu, return |nil| for no menu.
-  virtual NSMenu* GetMenu();
-
-  // Gets the font used to draw text in the decoration.
-  virtual NSFont* GetFont() const;
-
-  // Gets the accessibility NSView for this decoration. This NSView is
-  // a transparent button that is positioned over this decoration to allow it to
-  // accept keyboard focus and keyboard activations.
-  virtual NSView* GetAccessibilityView();
-
-  // Helper to get where the bubble point should land. |frame| specifies the
-  // decorations' image rectangle. Defaults to |frame.origin| if not overriden.
-  // The return value is in the same coordinate system as |frame|.
-  virtual NSPoint GetBubblePointInFrame(NSRect frame);
-
-  // Gets the Material Design vector-based icon.
-  NSImage* GetMaterialIcon(bool location_bar_is_dark) const;
-
-  static void DrawLabel(NSString* label,
-                        NSDictionary* attributes,
-                        const NSRect& frame);
-  static void DrawAttributedString(NSAttributedString* str,
-                                   const NSRect& frame);
-  static NSSize GetLabelSize(NSString* label,
-                             NSDictionary* attributes);
-
-  // Called when the accessibility view receives an action via a keyboard button
-  // press or VoiceOver activation. This method is public so it can be exposed
-  // to the private DecorationAccessibilityView helper class.
-  void OnAccessibilityViewAction();
-
-  // Called when the omnibox decoration changes state to update the
-  // accessibility view's attributes to match. The |apparent_frame| rectangle is
-  // the frame the accessibility view should appear at visually (which may be
-  // different from its frame in the Cocoa sense).
-  void UpdateAccessibilityView(NSRect apparent_frame);
-
-  // Computes the real bounds the focus ring should be drawn around for this
-  // decoration. Some decorations include visual spacing or separators in their
-  // bounds, but these should not be encompassed by the focus ring.
-  virtual NSRect GetRealFocusRingBounds(NSRect bounds) const;
-
-  DecorationMouseState state() const { return state_; }
-
-  bool active() const { return active_; }
-
-  // Width returned by |GetWidthForSpace()| when the item should be
-  // omitted for this width;
-  static const CGFloat kOmittedWidth;
-
-  // Material text color if the location bar is dark.
-  static const SkColor kMaterialDarkModeTextColor;
-
- protected:
-  // Returns the amount of padding between the divider and the label text.
-  virtual CGFloat DividerPadding() const;
-
-  // Gets the color used to draw the Material Design icon. The default
-  // implementation satisfies most cases - few subclasses should need to
-  // override.
-  virtual SkColor GetMaterialIconColor(bool location_bar_is_dark) const;
-
-  // Gets the decoration's Material Design vector icon. Subclasses should
-  // override to return the correct icon. Not an abstract method because some
-  // decorations are assigned their icon (vs. creating it themselves).
-  virtual const gfx::VectorIcon* GetMaterialVectorIcon() const;
-
-  // Draws the decoration's vertical divider. Assumes already lock focused on
-  // the control_view.
-  void DrawDivider(NSView* control_view,
-                   NSRect decoration_frame,
-                   CGFloat alpha) const;
-
- private:
-  friend class test::LocationBarDecorationTestApi;
-
-  // Called when the state of the decoration is updated.
-  void UpdateDecorationState();
-
-  bool visible_ = false;
-
-  // True if the decoration is active.
-  bool active_ = false;
-
-  // True if the decoration was active when the last mouse down was received.
-  bool was_active_in_last_mouse_down_ = false;
-
-  base::scoped_nsobject<NSControl> accessibility_view_;
-
-  // The decoration's tracking area. Only set if the decoration accepts a mouse
-  // press.
-  base::scoped_nsobject<CrTrackingArea> tracking_area_;
-
-  // The view that |tracking_area_| is added to.
-  NSView* tracking_area_owner_ = nullptr;
-
-  // Delegate object that handles mouseEntered: and mouseExited: events from
-  // the tracking area.
-  base::scoped_nsobject<DecorationMouseTrackingDelegate> tracking_delegate_;
-
-  // The state of the decoration.
-  DecorationMouseState state_ = DecorationMouseState::NONE;
-
-  DISALLOW_COPY_AND_ASSIGN(LocationBarDecoration);
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOCATION_BAR_LOCATION_BAR_DECORATION_H_
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
deleted file mode 100644
index 636bb40d4..0000000
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_decoration.mm
+++ /dev/null
@@ -1,502 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
-
-#include "base/logging.h"
-#include "base/mac/scoped_nsobject.h"
-#include "chrome/browser/ui/cocoa/l10n_util.h"
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#import "ui/base/cocoa/tracking_area.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/gfx/paint_vector_icon.h"
-
-namespace {
-
-// Layout and color values for the vertical divider.
-const CGFloat kDecorationDividerHeight = 16.0;
-const CGFloat kDecorationDividerPadding =
-    6.0;  // Between the divider and label.
-const CGFloat kDecorationDividerGray = 0xFFA6A6A6;
-const CGFloat kDecorationDividerGrayIncognito = 0xFFCCCCCC;
-
-// Color values for the hover and pressed background.
-const SkColor kHoverBackgroundColor = 0x14000000;
-const SkColor kHoverDarkBackgroundColor = 0x1EFFFFFF;
-const SkColor kPressedBackgroundColor = 0x1E000000;
-const SkColor kPressedDarkBackgroundColor = 0x3DFFFFFF;
-
-// Amount of inset for the background frame.
-const CGFloat kDecorationBackgroundFrameYInset = 2.0;
-
-}  // namespace
-
-// A DecorationAccessibilityView is a focusable, pressable button that is fully
-// transparent and cannot be hit by mouse clicks. This is overlaid over a drawn
-// decoration, to fake keyboard focus on the decoration and make it visible to
-// VoiceOver.
-@interface DecorationAccessibilityView : NSButton {
-  LocationBarDecoration* owner_;  // weak
-  NSRect apparentFrame_;
-}
-
-// NSView:
-- (id)initWithOwner:(LocationBarDecoration*)owner;
-- (BOOL)acceptsFirstResponder;
-- (void)drawRect:(NSRect)dirtyRect;
-- (NSView*)hitTest:(NSPoint)aPoint;
-- (NSString*)accessibilityLabel;
-
-// This method is called when this DecorationAccessibilityView is activated.
-- (void)actionDidHappen;
-
-- (void)setApparentFrame:(NSRect)r;
-@end
-
-@implementation DecorationAccessibilityView
-
-- (id)initWithOwner:(LocationBarDecoration*)owner {
-  if ((self = [super initWithFrame:NSZeroRect])) {
-    self.bordered = NO;
-    self.focusRingType = NSFocusRingTypeExterior;
-    self->owner_ = owner;
-    [self setAction:@selector(actionDidHappen)];
-    [self setTarget:self];
-    self->apparentFrame_ = NSZeroRect;
-  }
-  return self;
-}
-
-- (BOOL)acceptsFirstResponder {
-  // This NSView is only focusable if the owning LocationBarDecoration can
-  // accept mouse presses.
-  return owner_->AcceptsMousePress() == AcceptsPress::NEVER ? NO : YES;
-}
-
-- (void)drawRect:(NSRect)dirtyRect {
-  // Draw nothing. This NSView is fully transparent.
-}
-
-- (NSView*)hitTest:(NSPoint)aPoint {
-  // Mouse clicks cannot hit this NSView.
-  return nil;
-}
-
-- (void)actionDidHappen {
-  owner_->OnAccessibilityViewAction();
-}
-
-- (NSString*)accessibilityLabel {
-  NSString* label = owner_->GetAccessibilityLabel();
-  return label ? label : owner_->GetToolTip();
-}
-
-- (void)setApparentFrame:(NSRect)r {
-  apparentFrame_ = r;
-}
-
-// The focus ring (and all other visuals) should be positioned using the
-// apparent frame, not the real frame, because of the hack in
-// LocationBarViewMac::UpdateAccessibilityView().
-- (void)drawFocusRingMask {
-  NSRectFill([self focusRingMaskBounds]);
-}
-
-- (NSRect)focusRingMaskBounds {
-  return owner_->GetRealFocusRingBounds(
-      [[self superview] convertRect:apparentFrame_ toView:self]);
-}
-
-@end
-
-@interface DecorationMouseTrackingDelegate : NSObject {
-  LocationBarDecoration* owner_;  // weak
-}
-
-- (id)initWithOwner:(LocationBarDecoration*)owner;
-- (void)mouseEntered:(NSEvent*)event;
-- (void)mouseExited:(NSEvent*)event;
-
-@end
-
-@implementation DecorationMouseTrackingDelegate
-
-- (id)initWithOwner:(LocationBarDecoration*)owner {
-  if ((self = [super init])) {
-    owner_ = owner;
-  }
-
-  return self;
-}
-
-- (void)mouseEntered:(NSEvent*)event {
-  owner_->OnMouseEntered();
-}
-
-- (void)mouseExited:(NSEvent*)event {
-  owner_->OnMouseExited();
-}
-
-@end
-
-const CGFloat LocationBarDecoration::kOmittedWidth = 0.0;
-const SkColor LocationBarDecoration::kMaterialDarkModeTextColor = SK_ColorWHITE;
-
-LocationBarDecoration::LocationBarDecoration() {
-  accessibility_view_.reset(
-      [[DecorationAccessibilityView alloc] initWithOwner:this]);
-  [accessibility_view_.get() setHidden:YES];
-}
-
-void LocationBarDecoration::OnAccessibilityViewAction() {
-  DCHECK(!IsAccessibilityIgnored());
-  // Turn the action into a synthesized mouse click at the center of |this|.
-  NSRect frame = [accessibility_view_.get() frame];
-  NSPoint mousePoint = NSMakePoint(NSMidX(frame), NSMidY(frame));
-  HandleMousePressed(frame, mousePoint);
-}
-
-LocationBarDecoration::~LocationBarDecoration() {
-  [accessibility_view_.get() removeFromSuperview];
-}
-
-CGFloat LocationBarDecoration::DividerPadding() const {
-  return kDecorationDividerPadding;
-}
-
-bool LocationBarDecoration::IsVisible() const {
-  return visible_;
-}
-
-void LocationBarDecoration::SetVisible(bool visible) {
-  visible_ = visible;
-  bool a11y_hidden = !visible || IsAccessibilityIgnored();
-  [accessibility_view_.get() setHidden:a11y_hidden];
-}
-
-
-CGFloat LocationBarDecoration::GetWidthForSpace(CGFloat width) {
-  NOTREACHED();
-  return kOmittedWidth;
-}
-
-NSRect LocationBarDecoration::GetBackgroundFrame(NSRect frame) {
-  return NSInsetRect(frame, 0.0, kDecorationBackgroundFrameYInset);
-}
-
-void LocationBarDecoration::UpdateAccessibilityView(NSRect apparent_frame) {
-  auto v = static_cast<DecorationAccessibilityView*>(accessibility_view_);
-  [accessibility_view_ setEnabled:AcceptsMousePress() != AcceptsPress::NEVER];
-  [v setApparentFrame:apparent_frame];
-}
-
-NSRect LocationBarDecoration::GetRealFocusRingBounds(NSRect bounds) const {
-  return bounds;
-}
-
-void LocationBarDecoration::DrawInFrame(NSRect frame, NSView* control_view) {
-  NOTREACHED();
-}
-
-void LocationBarDecoration::DrawWithBackgroundInFrame(NSRect frame,
-                                                      NSView* control_view) {
-  // Draw the background if available.
-  if ((active_ || state_ != DecorationMouseState::NONE) &&
-      HasHoverAndPressEffect()) {
-    bool in_dark_mode = [[control_view window] inIncognitoModeWithSystemTheme];
-
-    SkColor background_color;
-    if (active_ || state_ == DecorationMouseState::PRESSED) {
-      background_color =
-          in_dark_mode ? kPressedDarkBackgroundColor : kPressedBackgroundColor;
-    } else {
-      background_color =
-          in_dark_mode ? kHoverDarkBackgroundColor : kHoverBackgroundColor;
-    }
-
-    [skia::SkColorToSRGBNSColor(background_color) setFill];
-
-    NSBezierPath* path = [NSBezierPath bezierPath];
-    [path appendBezierPathWithRoundedRect:GetBackgroundFrame(frame)
-                                  xRadius:2
-                                  yRadius:2];
-    [path fill];
-  }
-  DrawInFrame(frame, control_view);
-}
-
-NSString* LocationBarDecoration::GetToolTip() {
-  return nil;
-}
-
-NSString* LocationBarDecoration::GetAccessibilityLabel() {
-  return nil;
-}
-
-bool LocationBarDecoration::IsAccessibilityIgnored() {
-  return false;
-}
-
-NSRect LocationBarDecoration::GetTrackingFrame(NSRect frame) {
-  return frame;
-}
-
-CrTrackingArea* LocationBarDecoration::SetupTrackingArea(NSRect frame,
-                                                         NSView* control_view) {
-  if (!HasHoverAndPressEffect() || !control_view)
-    return nil;
-
-  NSRect tracking_frame = GetTrackingFrame(frame);
-  if (control_view == tracking_area_owner_ && tracking_area_.get() &&
-      NSEqualRects([tracking_area_ rect], tracking_frame)) {
-    return tracking_area_.get();
-  }
-
-  if (tracking_area_owner_)
-    [tracking_area_owner_ removeTrackingArea:tracking_area_.get()];
-
-  if (!tracking_delegate_) {
-    tracking_delegate_.reset(
-        [[DecorationMouseTrackingDelegate alloc] initWithOwner:this]);
-  }
-
-  tracking_area_.reset([[CrTrackingArea alloc]
-      initWithRect:tracking_frame
-           options:NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow
-             owner:tracking_delegate_.get()
-          userInfo:nil]);
-
-  [control_view addTrackingArea:tracking_area_.get()];
-  tracking_area_owner_ = control_view;
-
-  state_ = [tracking_area_ mouseInsideTrackingAreaForView:control_view]
-               ? DecorationMouseState::HOVER
-               : DecorationMouseState::NONE;
-
-  return tracking_area_.get();
-}
-
-void LocationBarDecoration::RemoveTrackingArea() {
-  DCHECK(tracking_area_owner_);
-  DCHECK(tracking_area_);
-  [tracking_area_owner_ removeTrackingArea:tracking_area_.get()];
-  tracking_area_owner_ = nullptr;
-  tracking_area_.reset();
-}
-
-AcceptsPress LocationBarDecoration::AcceptsMousePress() {
-  return AcceptsPress::NEVER;
-}
-
-bool LocationBarDecoration::HasHoverAndPressEffect() {
-  return AcceptsMousePress() != AcceptsPress::NEVER;
-}
-
-bool LocationBarDecoration::IsDraggable() {
-  return false;
-}
-
-NSImage* LocationBarDecoration::GetDragImage() {
-  return nil;
-}
-
-NSRect LocationBarDecoration::GetDragImageFrame(NSRect frame) {
-  return NSZeroRect;
-}
-
-NSPasteboard* LocationBarDecoration::GetDragPasteboard() {
-  return nil;
-}
-
-bool LocationBarDecoration::HandleMousePressed(NSRect frame, NSPoint location) {
-  if (was_active_in_last_mouse_down_) {
-    was_active_in_last_mouse_down_ = false;
-    if (AcceptsMousePress() == AcceptsPress::WHEN_ACTIVATED) {
-      // Clear the active state. This is usually the responsibility of the popup
-      // code (i.e. whatever called SetActive(true)). However, there exist some
-      // tricky lifetimes and corner cases where a client may "forget", or be
-      // unable to clear the active state. In that case, we risk getting "stuck"
-      // in a state where client code may never receive a signal. Clearing the
-      // active state here ensures a subsequent click will always send a signal.
-      SetActive(false);
-      return true;
-    }
-  }
-
-  return OnMousePressed(frame, location);
-}
-
-bool LocationBarDecoration::OnMousePressed(NSRect frame, NSPoint location) {
-  return false;
-}
-
-void LocationBarDecoration::OnMouseDown() {
-  was_active_in_last_mouse_down_ = active_;
-  state_ = DecorationMouseState::PRESSED;
-  UpdateDecorationState();
-}
-
-void LocationBarDecoration::OnMouseUp() {
-  // Ignore the mouse up if it's not associated with a mouse down event.
-  if (state_ != DecorationMouseState::PRESSED)
-    return;
-
-  DCHECK(tracking_area_owner_);
-  state_ = [tracking_area_ mouseInsideTrackingAreaForView:tracking_area_owner_]
-               ? DecorationMouseState::HOVER
-               : DecorationMouseState::NONE;
-  UpdateDecorationState();
-}
-
-void LocationBarDecoration::OnMouseEntered() {
-  state_ = DecorationMouseState::HOVER;
-  UpdateDecorationState();
-}
-
-void LocationBarDecoration::OnMouseExited() {
-  state_ = DecorationMouseState::NONE;
-  UpdateDecorationState();
-}
-
-void LocationBarDecoration::SetActive(bool active) {
-  if (active_ == active)
-    return;
-
-  active_ = active;
-  state_ = [tracking_area_ mouseInsideTrackingAreaForView:tracking_area_owner_]
-               ? DecorationMouseState::HOVER
-               : DecorationMouseState::NONE;
-  UpdateDecorationState();
-}
-
-void LocationBarDecoration::UpdateDecorationState() {
-  if (tracking_area_owner_)
-    [tracking_area_owner_ setNeedsDisplay:YES];
-}
-
-NSMenu* LocationBarDecoration::GetMenu() {
-  return nil;
-}
-
-NSFont* LocationBarDecoration::GetFont() const {
-  return OmniboxViewMac::GetNormalFieldFont();
-}
-
-NSView* LocationBarDecoration::GetAccessibilityView() {
-  return accessibility_view_.get();
-}
-
-NSPoint LocationBarDecoration::GetBubblePointInFrame(NSRect frame) {
-  // Clients that use a bubble should implement this. Can't be abstract
-  // because too many LocationBarDecoration subclasses don't use a bubble.
-  // Can't live on subclasses only because it needs to be on a shared API.
-  NOTREACHED();
-  return frame.origin;
-}
-
-NSImage* LocationBarDecoration::GetMaterialIcon(
-    bool location_bar_is_dark) const {
-  const int kIconSize = 16;
-  const gfx::VectorIcon* vector_icon = GetMaterialVectorIcon();
-  if (!vector_icon) {
-    // Return an empty image when the decoration specifies no vector icon, so
-    // that its bubble is positioned correctly (the position is based on the
-    // width of the image; returning nil will mess up the positioning).
-    NSSize icon_size = NSMakeSize(kIconSize, kIconSize);
-    return [[[NSImage alloc] initWithSize:icon_size] autorelease];
-  }
-
-  SkColor vector_icon_color = GetMaterialIconColor(location_bar_is_dark);
-  return NSImageFromImageSkia(
-      gfx::CreateVectorIcon(*vector_icon, kIconSize, vector_icon_color));
-}
-
-// static
-void LocationBarDecoration::DrawLabel(NSString* label,
-                                      NSDictionary* attributes,
-                                      const NSRect& frame) {
-  base::scoped_nsobject<NSAttributedString> str(
-      [[NSAttributedString alloc] initWithString:label attributes:attributes]);
-  DrawAttributedString(str, frame);
-}
-
-// static
-void LocationBarDecoration::DrawAttributedString(NSAttributedString* str,
-                                                 const NSRect& frame) {
-  NSRect text_rect = frame;
-  text_rect.size.height = [str size].height;
-  text_rect.origin.y = roundf(NSMidY(frame) - NSHeight(text_rect) / 2.0) - 1;
-  [str drawInRect:text_rect];
-}
-
-// static
-NSSize LocationBarDecoration::GetLabelSize(NSString* label,
-                                           NSDictionary* attributes) {
-  return [label sizeWithAttributes:attributes];
-}
-
-SkColor LocationBarDecoration::GetMaterialIconColor(
-    bool location_bar_is_dark) const {
-  return location_bar_is_dark ? SK_ColorWHITE : gfx::kChromeIconGrey;
-}
-
-void LocationBarDecoration::DrawDivider(NSView* control_view,
-                                        NSRect decoration_frame,
-                                        CGFloat alpha) const {
-  if (alpha == 0.0) {
-    return;
-  }
-
-  NSBezierPath* line = [NSBezierPath bezierPath];
-
-  CGFloat line_width = [control_view cr_lineWidth];
-  [line setLineWidth:line_width];
-
-  const BOOL is_rtl = cocoa_l10n_util::ShouldDoExperimentalRTLLayout();
-  NSPoint divider_origin = NSZeroPoint;
-  divider_origin.x = is_rtl ? NSMinX(decoration_frame) + DividerPadding()
-                            : NSMaxX(decoration_frame) - DividerPadding();
-  // Screen pixels lay between integral coordinates in user space. If you
-  // draw a line from (16, 16) to (16, 32), Core Graphics maps that line to
-  // the pixels that lay along x=16.5. In order to achieve a line that
-  // appears to lay along x=16, CG will perform dithering. To get a crisp
-  // line, you have to specify x=16.5, so translating by 1/2 the 1-pixel
-  // line width creates the crisp line we want. We subtract to better center
-  // the line between the label and URL.
-  divider_origin.x -= line_width / 2.;
-  CGFloat divider_y_frame_offset =
-      (NSHeight(decoration_frame) - kDecorationDividerHeight) / 2.0;
-  divider_origin.y = NSMinY(decoration_frame) + divider_y_frame_offset;
-  // Adjust the divider origin by 1/2 a point to visually center the
-  // divider vertically on Retina.
-  if (line_width < 1) {
-    divider_origin.y -= 0.5;
-  }
-  [line moveToPoint:divider_origin];
-  [line relativeLineToPoint:NSMakePoint(0, kDecorationDividerHeight)];
-
-  NSColor* divider_color = nil;
-  bool location_bar_is_dark =
-      [[control_view window] inIncognitoModeWithSystemTheme];
-  if (location_bar_is_dark) {
-    divider_color = skia::SkColorToSRGBNSColor(kDecorationDividerGrayIncognito);
-  } else {
-    divider_color = skia::SkColorToSRGBNSColor(kDecorationDividerGray);
-  }
-
-  if (alpha < 1) {
-    divider_color = [divider_color colorWithAlphaComponent:alpha];
-  }
-  [divider_color set];
-  [line stroke];
-}
-
-const gfx::VectorIcon* LocationBarDecoration::GetMaterialVectorIcon() const {
-  NOTREACHED();
-  return nullptr;
-}
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
index 43ccc28..4d60858 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h
@@ -13,46 +13,23 @@
 
 #include "base/macros.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
 #include "chrome/browser/ui/location_bar/location_bar.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h"
-#include "chrome/browser/ui/page_action/page_action_icon_container.h"
-#include "components/content_settings/core/common/content_settings_types.h"
 #include "components/prefs/pref_member.h"
 #include "components/security_state/core/security_state.h"
-#include "components/zoom/zoom_event_manager_observer.h"
 
-@class AutocompleteTextField;
 class CommandUpdater;
-class LocationBarDecoration;
 class Profile;
 
-namespace {
-class LocationBarViewMacTest;
-}
-
-// Enumeration of the type of verbose that is displayed on the page info
-// decoration.
-enum class PageInfoVerboseType {
-  kNone = 0,
-  kSecurity,
-  kEVCert,
-  kChrome,
-  kExtension
-};
-
 // A C++ bridge class that represents the location bar UI element to
 // the portable code.  Wires up an OmniboxViewMac instance to
 // the location bar text field, which handles most of the work.
 
 class LocationBarViewMac : public LocationBar,
                            public LocationBarTesting,
-                           public ChromeOmniboxEditController,
-                           public PageActionIconContainer,
-                           public zoom::ZoomEventManagerObserver {
+                           public ChromeOmniboxEditController {
  public:
-  LocationBarViewMac(AutocompleteTextField* field,
-                     CommandUpdater* command_updater,
+  LocationBarViewMac(CommandUpdater* command_updater,
                      Profile* profile,
                      Browser* browser);
   ~LocationBarViewMac() override;
@@ -83,125 +60,13 @@
   bool TestContentSettingImagePressed(size_t index) override;
   bool IsContentSettingBubbleShowing(size_t index) override;
 
-  // Set/Get the editable state of the field.
-  void SetEditable(bool editable);
-  bool IsEditable();
-
-  // Happens when the zoom changes for the active tab. |can_show_bubble| is
-  // false when the change in zoom for the active tab wasn't an explicit user
-  // action (e.g. switching tabs, creating a new tab, creating a new browser).
-  // Additionally, |can_show_bubble| will only be true when the bubble wouldn't
-  // be obscured by other UI (app menu) or redundant (+/- from app menu).
-  void ZoomChangedForActiveTab(bool can_show_bubble);
-
-  // Get the point in window coordinates in the |decoration| at which the
-  // associate bubble aims.
-  NSPoint GetBubblePointForDecoration(LocationBarDecoration* decoration) const;
-
-  // When any image decorations change, call this to ensure everything is
-  // redrawn and laid out if necessary.
-  void OnDecorationsChanged();
-
-  // Layout the various decorations which live in the field.
-  void Layout();
-
-  // Re-draws |decoration| if it's already being displayed.
-  void RedrawDecoration(LocationBarDecoration* decoration);
-
-  // Updates the controller, and, if |contents| is non-null, restores saved
-  // state that the tab holds.
-  void Update(const content::WebContents* contents);
-
-  // Clears any location bar state stored for |contents|.
-  void ResetTabState(content::WebContents* contents);
-
-  // Set the location bar's icon to the correct image for the current URL.
-  void UpdateLocationIcon();
-
-  // Set the location bar's controls to visibly match the current theme.
-  void UpdateColorsToMatchTheme();
-
-  // Notify the location bar that it was added to the browser window. Provides
-  // an update point for interface objects that need to set their appearance
-  // based on the window's theme.
-  void OnAddedToWindow();
-
-  // Notify the location bar that the browser window theme has changed. Provides
-  // an update point for interface objects that need to set their appearance
-  // based on the window's theme.
-  void OnThemeChanged();
-
   // ChromeOmniboxEditController:
-  void UpdateWithoutTabRestore() override;
-  void OnChanged() override;
   ToolbarModel* GetToolbarModel() override;
   const ToolbarModel* GetToolbarModel() const override;
-  content::WebContents* GetWebContents() override;
-
-  // PageActionIconContainer:
-  void UpdatePageActionIcon(PageActionIconType) override;
-
-  PageInfoVerboseType GetPageInfoVerboseType() const;
-
-  // Returns true if the page info decoration should display security verbose.
-  // The verbose should only be shown for valid and invalid HTTPS states.
-  bool HasSecurityVerboseText() const;
-
-  NSImage* GetKeywordImage(const base::string16& keyword);
-
-  // Returns the color for the vector icon in the location bar.
-  SkColor GetLocationBarIconColor() const;
-
-  AutocompleteTextField* GetAutocompleteTextField() { return field_; }
-
-  // Returns true if the location bar is dark.
-  bool IsLocationBarDark() const;
-
-  Browser* browser() const { return browser_; }
-
-  // ZoomManagerObserver:
-  // Updates the view for the zoom icon when default zoom levels change.
-  void OnDefaultZoomLevelChanged() override;
-
-  // Returns the decoration accessibility views for all of this
-  // LocationBarViewMac's decorations. The returned NSViews may not have been
-  // positioned yet.
-  std::vector<NSView*> GetDecorationAccessibilityViews();
 
  private:
-  friend class LocationBarViewMacTest;
-
-  // Posts |notification| to the default notification center.
-  void PostNotification(NSString* notification);
-
-  void OnEditBookmarksEnabledChanged();
-
-  // Updates visibility of the content settings icons based on the current
-  // tab contents state.
-  bool RefreshContentSettingsDecorations();
-
-  // Returns pointers to all of the LocationBarDecorations owned by this
-  // LocationBarViewMac. This helper function is used for positioning and
-  // re-positioning accessibility views.
-  std::vector<LocationBarDecoration*> GetDecorations();
-
-  // Updates |decoration|'s accessibility view's position to match the computed
-  // position the decoration will be drawn at, and update its enabled state
-  // based on whether |decoration| is accepting presses currently.
-  void UpdateAccessibilityView(LocationBarDecoration* decoration);
-
-  std::unique_ptr<OmniboxViewMac> omnibox_view_;
-
-  AutocompleteTextField* field_;  // owned by tab controller
-
   Browser* browser_;
 
-  // Used to change the visibility of the star decoration.
-  BooleanPrefMember edit_bookmarks_enabled_;
-
-  // Indicates whether or not the location bar is currently visible.
-  bool location_bar_visible_;
-
   DISALLOW_COPY_AND_ASSIGN(LocationBarViewMac);
 };
 
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
index d01fea9..5611e018 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -4,108 +4,14 @@
 
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#import "base/mac/mac_util.h"
-#include "base/stl_util.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/app/chrome_command_ids.h"
-#import "chrome/browser/app_controller_mac.h"
-#include "chrome/browser/command_updater.h"
-#include "chrome/browser/defaults.h"
-#include "chrome/browser/extensions/api/omnibox/omnibox_api.h"
-#include "chrome/browser/extensions/extension_ui_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/search_engines/template_url_service_factory.h"
-#include "chrome/browser/translate/chrome_translate_client.h"
-#include "chrome/browser/translate/translate_service.h"
-#include "chrome/browser/ui/autofill/save_card_bubble_controller_impl.h"
-#include "chrome/browser/ui/browser_list.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-#import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
-#include "chrome/browser/ui/content_settings/content_setting_bubble_model.h"
-#include "chrome/browser/ui/content_settings/content_setting_image_model.h"
-#include "chrome/browser/ui/page_info/page_info_dialog.h"
-#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/grit/chromium_strings.h"
-#include "components/bookmarks/common/bookmark_pref_names.h"
-#import "components/omnibox/browser/omnibox_popup_model.h"
-#include "components/prefs/pref_service.h"
-#include "components/search_engines/template_url.h"
-#include "components/search_engines/template_url_service.h"
-#include "components/toolbar/vector_icons.h"
-#include "components/translate/core/browser/language_state.h"
-#include "components/variations/variations_associated_data.h"
-#include "components/vector_icons/vector_icons.h"
-#include "components/zoom/zoom_controller.h"
-#include "components/zoom/zoom_event_manager.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/url_constants.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "ui/base/cocoa/cocoa_base_utils.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/color_utils.h"
-#include "ui/gfx/image/image.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/gfx/paint_vector_icon.h"
-
-using content::WebContents;
-
-namespace {
-
-const int kDefaultIconSize = 16;
-
-// Color of the vector graphic icons when the location bar is dark.
-// SkColorSetARGB(0xCC, 0xFF, 0xFF 0xFF);
-const SkColor kMaterialDarkVectorIconColor = SK_ColorWHITE;
-
-}  // namespace
-
-// TODO(shess): This code is mostly copied from the gtk
-// implementation.  Make sure it's all appropriate and flesh it out.
-
-LocationBarViewMac::LocationBarViewMac(AutocompleteTextField* field,
-                                       CommandUpdater* command_updater,
+LocationBarViewMac::LocationBarViewMac(CommandUpdater* command_updater,
                                        Profile* profile,
                                        Browser* browser)
     : LocationBar(profile),
       ChromeOmniboxEditController(command_updater),
-      omnibox_view_(new OmniboxViewMac(this, profile, command_updater, field)),
-      field_(field),
-      browser_(browser),
-      location_bar_visible_(true) {
-  edit_bookmarks_enabled_.Init(
-      bookmarks::prefs::kEditBookmarksEnabled, profile->GetPrefs(),
-      base::Bind(&LocationBarViewMac::OnEditBookmarksEnabledChanged,
-                 base::Unretained(this)));
-
-  zoom::ZoomEventManager::GetForBrowserContext(profile)->AddObserver(this);
-
-  [[field_ cell] setIsPopupMode:
-      !browser->SupportsWindowFeature(Browser::FEATURE_TABSTRIP)];
-
-  // Sets images for the decorations, and performs a layout. This call ensures
-  // that this class is in a consistent state after initialization.
-  OnChanged();
-}
+      browser_(browser) {}
 
 LocationBarViewMac::~LocationBarViewMac() {
-  // Disconnect from cell in case it outlives us.
-  [[field_ cell] clearDecorations];
-
-  zoom::ZoomEventManager::GetForBrowserContext(profile())->RemoveObserver(this);
 }
 
 GURL LocationBarViewMac::GetDestinationURL() const {
@@ -125,23 +31,16 @@
 }
 
 void LocationBarViewMac::AcceptInput() {
-  AcceptInput(base::TimeTicks());
 }
 
 void LocationBarViewMac::AcceptInput(
     base::TimeTicks match_selection_timestamp) {
-  WindowOpenDisposition disposition =
-      ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
-  omnibox_view_->model()->AcceptInput(disposition, false,
-                                      match_selection_timestamp);
 }
 
 void LocationBarViewMac::FocusLocation(bool select_all) {
-  omnibox_view_->FocusLocation(select_all);
 }
 
 void LocationBarViewMac::FocusSearch() {
-  omnibox_view_->EnterKeywordModeForDefaultSearchProvider();
 }
 
 void LocationBarViewMac::UpdateContentSettingsIcons() {
@@ -154,8 +53,6 @@
 }
 
 void LocationBarViewMac::UpdateLocalCardMigrationIcon() {
-  // TODO(crbug.com/859652): Implement for mac.
-  NOTIMPLEMENTED();
 }
 
 void LocationBarViewMac::UpdateBookmarkStarVisibility() {
@@ -163,31 +60,19 @@
 
 void LocationBarViewMac::UpdateLocationBarVisibility(bool visible,
                                                      bool animate) {
-  // Track the target location bar visibility to avoid redundant transitions
-  // being initiated when one is already in progress.
-  if (visible != location_bar_visible_) {
-    [[[BrowserWindowController browserWindowControllerForView:field_]
-        toolbarController] updateVisibility:visible
-                              withAnimation:animate];
-    location_bar_visible_ = visible;
-  }
 }
 
-void LocationBarViewMac::SaveStateToContents(WebContents* contents) {
-  // TODO(shess): Why SaveStateToContents vs SaveStateToTab?
-  omnibox_view_->SaveStateToTab(contents);
-}
+void LocationBarViewMac::SaveStateToContents(content::WebContents* contents) {}
 
 void LocationBarViewMac::Revert() {
-  omnibox_view_->RevertAll();
 }
 
 const OmniboxView* LocationBarViewMac::GetOmniboxView() const {
-  return omnibox_view_.get();
+  return nullptr;
 }
 
 OmniboxView* LocationBarViewMac::GetOmniboxView() {
-  return omnibox_view_.get();
+  return nullptr;
 }
 
 LocationBarTesting* LocationBarViewMac::GetLocationBarForTesting() {
@@ -206,107 +91,6 @@
   return false;
 }
 
-void LocationBarViewMac::SetEditable(bool editable) {
-  [field_ setEditable:editable ? YES : NO];
-  UpdateBookmarkStarVisibility();
-  Layout();
-}
-
-bool LocationBarViewMac::IsEditable() {
-  return [field_ isEditable] ? true : false;
-}
-
-void LocationBarViewMac::ZoomChangedForActiveTab(bool can_show_bubble) {
-}
-
-NSPoint LocationBarViewMac::GetBubblePointForDecoration(
-    LocationBarDecoration* decoration) const {
-  return [field_ bubblePointForDecoration:decoration];
-}
-
-void LocationBarViewMac::OnDecorationsChanged() {
-}
-
-// TODO(shess): This function should over time grow to closely match
-// the views Layout() function.
-void LocationBarViewMac::Layout() {
-  AutocompleteTextFieldCell* cell = [field_ cell];
-
-  // Reset the leading decorations.
-  // TODO(shess): Shortly, this code will live somewhere else, like in
-  // the constructor.  I am still wrestling with how best to deal with
-  // right-hand decorations, which are not a static set.
-  [cell clearDecorations];
-
-  // Get the keyword to use for keyword-search and hinting.
-  const base::string16 keyword = omnibox_view_->model()->keyword();
-  base::string16 short_name;
-  bool is_extension_keyword = false;
-  if (!keyword.empty()) {
-    short_name = TemplateURLServiceFactory::GetForProfile(profile())->
-        GetKeywordShortName(keyword, &is_extension_keyword);
-  }
-
-  // These need to change anytime the layout changes.
-  // TODO(shess): Anytime the field editor might have changed, the
-  // cursor rects almost certainly should have changed.  The tooltips
-  // might change even when the rects don't change.
-  OnDecorationsChanged();
-}
-
-void LocationBarViewMac::RedrawDecoration(LocationBarDecoration* decoration) {
-  AutocompleteTextFieldCell* cell = [field_ cell];
-  NSRect frame = [cell frameForDecoration:decoration
-                                  inFrame:[field_ bounds]];
-  if (!NSIsEmptyRect(frame))
-    [field_ setNeedsDisplayInRect:frame];
-}
-
-void LocationBarViewMac::ResetTabState(WebContents* contents) {
-  omnibox_view_->ResetTabState(contents);
-}
-
-void LocationBarViewMac::Update(const WebContents* contents) {
-  UpdateManagePasswordsIconAndBubble();
-  UpdateBookmarkStarVisibility();
-  UpdateSaveCreditCardIcon();
-  RefreshContentSettingsDecorations();
-  if (contents) {
-    omnibox_view_->OnTabChanged(contents);
-  } else {
-    omnibox_view_->Update();
-  }
-
-  OnChanged();
-}
-
-void LocationBarViewMac::UpdateWithoutTabRestore() {
-  Update(nullptr);
-}
-
-void LocationBarViewMac::UpdateLocationIcon() {
-}
-
-void LocationBarViewMac::UpdateColorsToMatchTheme() {
-  // Update the location-bar icon.
-  UpdateLocationIcon();
-
-  // Update the appearance of the text in the Omnibox.
-  omnibox_view_->Update();
-}
-
-void LocationBarViewMac::OnAddedToWindow() {
-  UpdateColorsToMatchTheme();
-}
-
-void LocationBarViewMac::OnThemeChanged() {
-  UpdateColorsToMatchTheme();
-}
-
-void LocationBarViewMac::OnChanged() {
-  UpdateLocationIcon();
-}
-
 ToolbarModel* LocationBarViewMac::GetToolbarModel() {
   return browser_->toolbar_model();
 }
@@ -314,109 +98,3 @@
 const ToolbarModel* LocationBarViewMac::GetToolbarModel() const {
   return browser_->toolbar_model();
 }
-
-WebContents* LocationBarViewMac::GetWebContents() {
-  return browser_->tab_strip_model()->GetActiveWebContents();
-}
-
-void LocationBarViewMac::UpdatePageActionIcon(PageActionIconType type) {
-}
-
-PageInfoVerboseType LocationBarViewMac::GetPageInfoVerboseType() const {
-  if (omnibox_view_->IsEditingOrEmpty() ||
-      omnibox_view_->model()->is_keyword_hint()) {
-    return PageInfoVerboseType::kNone;
-  } else if (GetToolbarModel()->GetSecurityLevel(false) ==
-             security_state::EV_SECURE) {
-    return PageInfoVerboseType::kEVCert;
-  } else if (GetToolbarModel()->GetURL().SchemeIs(
-                 extensions::kExtensionScheme)) {
-    return PageInfoVerboseType::kExtension;
-  } else if (GetToolbarModel()->GetURL().SchemeIs(content::kChromeUIScheme)) {
-    return PageInfoVerboseType::kChrome;
-  } else {
-    return PageInfoVerboseType::kSecurity;
-  }
-}
-
-bool LocationBarViewMac::HasSecurityVerboseText() const {
-  if (GetPageInfoVerboseType() != PageInfoVerboseType::kSecurity)
-    return false;
-
-  return !GetToolbarModel()->GetSecureVerboseText().empty();
-}
-
-bool LocationBarViewMac::IsLocationBarDark() const {
-  return [[field_ window] inIncognitoModeWithSystemTheme];
-}
-
-NSImage* LocationBarViewMac::GetKeywordImage(const base::string16& keyword) {
-  const TemplateURL* template_url = TemplateURLServiceFactory::GetForProfile(
-      profile())->GetTemplateURLForKeyword(keyword);
-  if (template_url &&
-      (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)) {
-    return extensions::OmniboxAPI::Get(profile())->
-        GetOmniboxIcon(template_url->GetExtensionId()).AsNSImage();
-  }
-
-  SkColor icon_color =
-      IsLocationBarDark() ? kMaterialDarkVectorIconColor : gfx::kGoogleBlue700;
-  return NSImageFromImageSkiaWithColorSpace(
-      gfx::CreateVectorIcon(vector_icons::kSearchIcon, kDefaultIconSize,
-                            icon_color),
-      base::mac::GetSRGBColorSpace());
-}
-
-SkColor LocationBarViewMac::GetLocationBarIconColor() const {
-  bool in_dark_mode = IsLocationBarDark();
-  if (in_dark_mode)
-    return kMaterialDarkVectorIconColor;
-
-  if (GetPageInfoVerboseType() == PageInfoVerboseType::kEVCert)
-    return gfx::kGoogleGreen700;
-
-  security_state::SecurityLevel security_level =
-      GetToolbarModel()->GetSecurityLevel(false);
-
-  if (security_level == security_state::NONE ||
-      security_level == security_state::HTTP_SHOW_WARNING) {
-    return gfx::kChromeIconGrey;
-  }
-
-  NSColor* srgb_color =
-      OmniboxViewMac::GetSecureTextColor(security_level, in_dark_mode);
-  NSColor* device_color =
-      [srgb_color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
-  return skia::NSDeviceColorToSkColor(device_color);
-}
-
-void LocationBarViewMac::PostNotification(NSString* notification) {
-  [[NSNotificationCenter defaultCenter] postNotificationName:notification
-                                        object:[NSValue valueWithPointer:this]];
-}
-
-void LocationBarViewMac::OnEditBookmarksEnabledChanged() {
-  UpdateBookmarkStarVisibility();
-  OnChanged();
-}
-
-bool LocationBarViewMac::RefreshContentSettingsDecorations() {
-  return false;
-}
-
-void LocationBarViewMac::UpdateAccessibilityView(
-    LocationBarDecoration* decoration) {
-}
-
-std::vector<LocationBarDecoration*> LocationBarViewMac::GetDecorations() {
-  std::vector<LocationBarDecoration*> decorations;
-  return decorations;
-}
-
-void LocationBarViewMac::OnDefaultZoomLevelChanged() {
-}
-
-std::vector<NSView*> LocationBarViewMac::GetDecorationAccessibilityViews() {
-  std::vector<NSView*> views;
-  return views;
-}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
deleted file mode 100644
index b54a3715..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_
-#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "components/omnibox/browser/autocomplete_match.h"
-
-class OmniboxPopupViewMac;
-
-@interface OmniboxPopupCellData : NSObject<NSCopying>
-
-// Left hand side of the separator (e.g. a hyphen).
-@property(readonly, retain, nonatomic) NSAttributedString* contents;
-
-// Right hand side of the separator (e.g. a hyphen).
-@property(readonly, retain, nonatomic) NSAttributedString* description;
-
-// NOTE: While |prefix_| is used only for tail suggestions, it still needs
-// to be a member of the class. This allows the |NSAttributedString| instance
-// to stay alive between the call to |drawTitle| and the actual paint event
-// which accesses the |NSAttributedString| instance.
-@property(readonly, retain, nonatomic) NSAttributedString* prefix;
-
-// Common icon that shows next to most rows in the list.
-@property(retain, nonatomic) NSImage* image;
-
-// Uncommon icon that only shows on answer rows (e.g. weather).
-@property(readonly, retain, nonatomic) NSImage* answerImage;
-
-@property(readonly, nonatomic) BOOL isContentsRTL;
-
-// Is this suggestion an answer or calculator result.
-@property(readonly, nonatomic) bool isAnswer;
-@property(readonly, nonatomic) AutocompleteMatch::Type matchType;
-@property(readonly, nonatomic) int maxLines;
-
-- (instancetype)initWithMatch:(const AutocompleteMatch&)matchFromModel
-                        image:(NSImage*)image
-                  answerImage:(NSImage*)answerImage
-                 forDarkTheme:(BOOL)isDarkTheme;
-
-// Returns the width of the match contents.
-- (CGFloat)getMatchContentsWidth;
-
-@end
-
-// Overrides how cells are displayed.  Uses information from
-// OmniboxPopupCellData to draw suggestion results.
-@interface OmniboxPopupCell : NSCell
-
-- (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView;
-
-// Returns the offset of the start of the contents in the input text for the
-// given match. It is costly to compute this offset, so it is computed once and
-// shared by all OmniboxPopupCell instances through OmniboxPopupViewMac parent.
-+ (CGFloat)computeContentsOffset:(const AutocompleteMatch&)match;
-
-+ (NSAttributedString*)createSeparatorStringForDarkTheme:(BOOL)isDarkTheme;
-
-+ (CGFloat)getTextContentAreaWidth:(CGFloat)cellContentMaxWidth;
-
-+ (CGFloat)getContentTextHeight;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_CELL_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
deleted file mode 100644
index 893665b..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
+++ /dev/null
@@ -1,656 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
-
-#include <stddef.h>
-
-#include <algorithm>
-#include <cmath>
-
-#include "base/i18n/rtl.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/objc_release_properties.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h"
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-#import "chrome/browser/ui/cocoa/themed_window.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/omnibox/browser/omnibox_field_trial.h"
-#include "components/omnibox/browser/omnibox_popup_model.h"
-#include "components/omnibox/browser/suggestion_answer.h"
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/font.h"
-
-namespace {
-
-// Extra padding beyond the vertical text padding.
-constexpr CGFloat kMaterialExtraVerticalImagePadding = 2.0;
-
-constexpr CGFloat kMaterialTextStartOffset = 27.0;
-
-constexpr CGFloat kMaterialImageXOffset = 6.0;
-
-constexpr CGFloat kDefaultVerticalMargin = 3.0;
-
-constexpr CGFloat kDefaultTextHeight = 19;
-
-// Returns the margin that should appear at the top and bottom of the result.
-CGFloat GetVerticalMargin() {
-  return base::GetFieldTrialParamByFeatureAsInt(
-      omnibox::kUIExperimentVerticalMargin,
-      OmniboxFieldTrial::kUIVerticalMarginParam, kDefaultVerticalMargin);
-}
-
-// Flips the given |rect| in context of the given |frame|.
-NSRect FlipIfRTL(NSRect rect, NSRect frame) {
-  DCHECK_LE(NSMinX(frame), NSMinX(rect));
-  DCHECK_GE(NSMaxX(frame), NSMaxX(rect));
-  if (base::i18n::IsRTL()) {
-    NSRect result = rect;
-    result.origin.x = NSMinX(frame) + (NSMaxX(frame) - NSMaxX(rect));
-    return result;
-  }
-  return rect;
-}
-
-NSColor* SelectedBackgroundColor(BOOL is_dark_theme) {
-  return is_dark_theme
-             ? skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorWHITE, 0x14))
-             : skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorBLACK, 0x14));
-}
-
-NSColor* HoveredBackgroundColor(BOOL is_dark_theme) {
-  return is_dark_theme
-             ? skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorWHITE, 0x0D))
-             : [NSColor controlHighlightColor];
-}
-
-NSColor* ContentTextColor(BOOL is_dark_theme) {
-  return is_dark_theme ? [NSColor whiteColor] : [NSColor blackColor];
-}
-NSColor* DimTextColor(BOOL is_dark_theme) {
-  return is_dark_theme
-             ? skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorWHITE, 0x7F))
-             : skia::SkColorToSRGBNSColor(SkColorSetRGB(0x64, 0x64, 0x64));
-}
-NSColor* InvisibleTextColor() {
-  return skia::SkColorToSRGBNSColor(SK_ColorTRANSPARENT);
-}
-NSColor* PositiveTextColor() {
-  return skia::SkColorToSRGBNSColor(SkColorSetRGB(0x3d, 0x94, 0x00));
-}
-NSColor* NegativeTextColor() {
-  return skia::SkColorToSRGBNSColor(SkColorSetRGB(0xdd, 0x4b, 0x39));
-}
-NSColor* URLTextColor(BOOL is_dark_theme) {
-  return is_dark_theme ? skia::SkColorToSRGBNSColor(gfx::kGoogleBlue300)
-                       : skia::SkColorToSRGBNSColor(gfx::kGoogleBlue700);
-}
-
-NSFont* FieldFont() {
-  return OmniboxViewMac::GetNormalFieldFont();
-}
-NSFont* BoldFieldFont() {
-  return OmniboxViewMac::GetBoldFieldFont();
-}
-NSFont* LargeFont() {
-  return OmniboxViewMac::GetLargeFont();
-}
-NSFont* LargeSuperscriptFont() {
-  NSFont* font = OmniboxViewMac::GetLargeFont();
-  // Calculate a slightly smaller font. The ratio here is somewhat arbitrary.
-  // Proportions from 5/9 to 5/7 all look pretty good.
-  CGFloat size = [font pointSize] * 5.0 / 9.0;
-  NSFontDescriptor* descriptor = [font fontDescriptor];
-  return [NSFont fontWithDescriptor:descriptor size:size];
-}
-
-// Sets the writing direction to |direction| for a given |range| of
-// |attributedString|.
-void SetTextDirectionForRange(NSMutableAttributedString* attributedString,
-                              NSWritingDirection direction,
-                              NSRange range) {
-  [attributedString
-      enumerateAttribute:NSParagraphStyleAttributeName
-                 inRange:range
-                 options:0
-              usingBlock:^(id paragraph_style, NSRange range, BOOL* stop) {
-                [paragraph_style setBaseWritingDirection:direction];
-              }];
-}
-
-NSAttributedString* CreateAnswerStringHelper(const base::string16& text,
-                                             NSInteger style_type,
-                                             bool is_bold,
-                                             BOOL is_dark_theme) {
-  NSDictionary* answer_style = nil;
-  NSFont* answer_font = nil;
-  switch (style_type) {
-    case SuggestionAnswer::TOP_ALIGNED:
-      answer_style = @{
-        NSForegroundColorAttributeName : DimTextColor(is_dark_theme),
-        NSFontAttributeName : LargeSuperscriptFont(),
-        NSSuperscriptAttributeName : @1
-      };
-      break;
-    case SuggestionAnswer::DESCRIPTION_NEGATIVE:
-      answer_style = @{
-        NSForegroundColorAttributeName : NegativeTextColor(),
-        NSFontAttributeName : LargeSuperscriptFont()
-      };
-      break;
-    case SuggestionAnswer::DESCRIPTION_POSITIVE:
-      answer_style = @{
-        NSForegroundColorAttributeName : PositiveTextColor(),
-        NSFontAttributeName : LargeSuperscriptFont()
-      };
-      break;
-    case SuggestionAnswer::PERSONALIZED_SUGGESTION:
-      answer_style = @{
-        NSForegroundColorAttributeName : ContentTextColor(is_dark_theme),
-        NSFontAttributeName : FieldFont()
-      };
-      break;
-    case SuggestionAnswer::ANSWER_TEXT_MEDIUM:
-      answer_style = @{
-        NSForegroundColorAttributeName : DimTextColor(is_dark_theme),
-        NSFontAttributeName : FieldFont()
-      };
-      break;
-    case SuggestionAnswer::ANSWER_TEXT_LARGE:
-      answer_style = @{
-        NSForegroundColorAttributeName : DimTextColor(is_dark_theme),
-        NSFontAttributeName : LargeFont()
-      };
-      break;
-    case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_SMALL:
-      answer_font = FieldFont();
-      answer_style = @{
-        NSForegroundColorAttributeName : DimTextColor(is_dark_theme),
-        NSFontAttributeName : answer_font
-      };
-      break;
-    case SuggestionAnswer::SUGGESTION_SECONDARY_TEXT_MEDIUM:
-      answer_font = LargeSuperscriptFont();
-      answer_style = @{
-        NSForegroundColorAttributeName : DimTextColor(is_dark_theme),
-        NSFontAttributeName : answer_font
-      };
-      break;
-    case SuggestionAnswer::SUGGESTION:  // Fall through.
-    default:
-      answer_style = @{
-        NSForegroundColorAttributeName : ContentTextColor(is_dark_theme),
-        NSFontAttributeName : FieldFont()
-      };
-      break;
-  }
-
-  if (is_bold) {
-    NSMutableDictionary* bold_style = [answer_style mutableCopy];
-    // TODO(dschuyler): Account for bolding fonts other than FieldFont.
-    // Field font is the only one currently necessary to bold.
-    [bold_style setObject:BoldFieldFont() forKey:NSFontAttributeName];
-    answer_style = bold_style;
-  }
-
-  return [[[NSAttributedString alloc]
-      initWithString:base::SysUTF16ToNSString(text)
-          attributes:answer_style] autorelease];
-}
-
-NSAttributedString* CreateAnswerString(const base::string16& text,
-                                       NSInteger style_type,
-                                       BOOL is_dark_theme) {
-  // TODO(dschuyler): make this better.  Right now this only supports unnested
-  // bold tags.  In the future we'll need to flag unexpected tags while adding
-  // support for b, i, u, sub, and sup.  We'll also need to support HTML
-  // entities (&lt; for '<', etc.).
-  const base::string16 begin_tag = base::ASCIIToUTF16("<b>");
-  const base::string16 end_tag = base::ASCIIToUTF16("</b>");
-  size_t begin = 0;
-  base::scoped_nsobject<NSMutableAttributedString> result(
-      [[NSMutableAttributedString alloc] init]);
-  while (true) {
-    size_t end = text.find(begin_tag, begin);
-    if (end == base::string16::npos) {
-      [result appendAttributedString:CreateAnswerStringHelper(
-                                         text.substr(begin), style_type, false,
-                                         is_dark_theme)];
-      break;
-    }
-    [result appendAttributedString:CreateAnswerStringHelper(
-                                       text.substr(begin, end - begin),
-                                       style_type, false, is_dark_theme)];
-    begin = end + begin_tag.length();
-    end = text.find(end_tag, begin);
-    if (end == base::string16::npos)
-      break;
-    [result appendAttributedString:CreateAnswerStringHelper(
-                                       text.substr(begin, end - begin),
-                                       style_type, true, is_dark_theme)];
-    begin = end + end_tag.length();
-  }
-  return result.autorelease();
-}
-
-NSAttributedString* CreateAnswerLine(const SuggestionAnswer::ImageLine& line,
-                                     BOOL is_dark_theme) {
-  base::scoped_nsobject<NSMutableAttributedString> answer_string(
-      [[NSMutableAttributedString alloc] init]);
-  DCHECK(!line.text_fields().empty());
-  for (const SuggestionAnswer::TextField& text_field : line.text_fields()) {
-    [answer_string appendAttributedString:CreateAnswerString(text_field.text(),
-                                                             text_field.type(),
-                                                             is_dark_theme)];
-  }
-  const base::string16 space(base::ASCIIToUTF16(" "));
-  const SuggestionAnswer::TextField* text_field = line.additional_text();
-  if (text_field) {
-    [answer_string
-        appendAttributedString:CreateAnswerString(space + text_field->text(),
-                                                  text_field->type(),
-                                                  is_dark_theme)];
-  }
-  text_field = line.status_text();
-  if (text_field) {
-    [answer_string
-        appendAttributedString:CreateAnswerString(space + text_field->text(),
-                                                  text_field->type(),
-                                                  is_dark_theme)];
-  }
-  base::scoped_nsobject<NSMutableParagraphStyle> style(
-      [[NSMutableParagraphStyle alloc] init]);
-  [style setTighteningFactorForTruncation:0.0];
-  [answer_string addAttribute:NSParagraphStyleAttributeName
-                            value:style
-                            range:NSMakeRange(0, [answer_string length])];
-  return answer_string.autorelease();
-}
-
-NSMutableAttributedString* CreateAttributedString(
-    const base::string16& text,
-    NSColor* text_color,
-    NSTextAlignment textAlignment) {
-  // Start out with a string using the default style info.
-  NSString* s = base::SysUTF16ToNSString(text);
-  NSDictionary* attributes = @{
-      NSFontAttributeName : FieldFont(),
-      NSForegroundColorAttributeName : text_color
-  };
-  NSMutableAttributedString* attributedString = [[
-      [NSMutableAttributedString alloc] initWithString:s
-                                            attributes:attributes] autorelease];
-
-  NSMutableParagraphStyle* style =
-      [[[NSMutableParagraphStyle alloc] init] autorelease];
-  [style setTighteningFactorForTruncation:0.0];
-  [style setAlignment:textAlignment];
-  if (@available(macOS 10.11, *))
-    [style setAllowsDefaultTighteningForTruncation:NO];
-  [attributedString addAttribute:NSParagraphStyleAttributeName
-                           value:style
-                           range:NSMakeRange(0, [attributedString length])];
-
-  return attributedString;
-}
-
-NSMutableAttributedString* CreateAttributedString(
-    const base::string16& text,
-    NSColor* text_color) {
-  return CreateAttributedString(text, text_color, NSNaturalTextAlignment);
-}
-
-NSAttributedString* CreateClassifiedAttributedString(
-    const base::string16& text,
-    NSColor* text_color,
-    const ACMatchClassifications& classifications,
-    BOOL is_dark_theme) {
-  NSMutableAttributedString* attributedString =
-      CreateAttributedString(text, text_color);
-  NSUInteger match_length = [attributedString length];
-
-  // Mark up the runs which differ from the default.
-  for (ACMatchClassifications::const_iterator i = classifications.begin();
-       i != classifications.end(); ++i) {
-    const bool is_last = ((i + 1) == classifications.end());
-    const NSUInteger next_offset =
-        (is_last ? match_length : static_cast<NSUInteger>((i + 1)->offset));
-    const NSUInteger location = static_cast<NSUInteger>(i->offset);
-    const NSUInteger length = next_offset - static_cast<NSUInteger>(i->offset);
-    // Guard against bad, off-the-end classification ranges.
-    if (location >= match_length || length <= 0)
-      break;
-    const NSRange range =
-        NSMakeRange(location, std::min(length, match_length - location));
-
-    if (0 != (i->style & ACMatchClassification::MATCH)) {
-      [attributedString addAttribute:NSFontAttributeName
-                               value:BoldFieldFont()
-                               range:range];
-    }
-
-    if (0 != (i->style & ACMatchClassification::URL)) {
-      // URLs have their text direction set to to LTR (avoids RTL characters
-      // making the URL render from right to left, as per RFC 3987 Section 4.1).
-      SetTextDirectionForRange(attributedString, NSWritingDirectionLeftToRight,
-                               range);
-      [attributedString addAttribute:NSForegroundColorAttributeName
-                               value:URLTextColor(is_dark_theme)
-                               range:range];
-    } else if (0 != (i->style & ACMatchClassification::DIM)) {
-      [attributedString addAttribute:NSForegroundColorAttributeName
-                               value:DimTextColor(is_dark_theme)
-                               range:range];
-    } else if (0 != (i->style & ACMatchClassification::INVISIBLE)) {
-      [attributedString addAttribute:NSForegroundColorAttributeName
-                               value:InvisibleTextColor()
-                               range:range];
-    }
-  }
-
-  return attributedString;
-}
-
-}  // namespace
-
-@interface OmniboxPopupCellData ()
-@end
-
-@interface OmniboxPopupCell ()
-- (CGFloat)drawMatchPart:(NSAttributedString*)attributedString
-               withFrame:(NSRect)cellFrame
-                  origin:(NSPoint)origin
-            withMaxWidth:(int)maxWidth
-            forDarkTheme:(BOOL)isDarkTheme
-           withHeightCap:(BOOL)hasHeightCap;
-- (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView;
-@end
-
-@implementation OmniboxPopupCellData
-
-@synthesize contents = contents_;
-@synthesize description = description_;
-@synthesize prefix = prefix_;
-@synthesize image = image_;
-@synthesize answerImage = answerImage_;
-@synthesize isContentsRTL = isContentsRTL_;
-@synthesize isAnswer = isAnswer_;
-@synthesize matchType = matchType_;
-@synthesize maxLines = maxLines_;
-
-- (instancetype)initWithMatch:(const AutocompleteMatch&)matchFromModel
-                        image:(NSImage*)image
-                  answerImage:(NSImage*)answerImage
-                 forDarkTheme:(BOOL)isDarkTheme {
-  if ((self = [super init])) {
-    image_ = [image retain];
-    answerImage_ = [answerImage retain];
-
-    AutocompleteMatch match =
-        matchFromModel.GetMatchWithContentsAndDescriptionPossiblySwapped();
-
-    isContentsRTL_ =
-        (base::i18n::RIGHT_TO_LEFT ==
-         base::i18n::GetFirstStrongCharacterDirection(match.contents));
-    matchType_ = match.type;
-
-    // Prefix may not have any characters with strong directionality, and may
-    // take the UI directionality. But prefix needs to appear in continuation
-    // of the contents so we force the directionality.
-    NSTextAlignment textAlignment =
-        isContentsRTL_ ? NSRightTextAlignment : NSLeftTextAlignment;
-    prefix_ = [CreateAttributedString(
-        base::UTF8ToUTF16(
-            match.GetAdditionalInfo(kACMatchPropertyContentsPrefix)),
-        ContentTextColor(isDarkTheme), textAlignment) retain];
-
-    isAnswer_ = !!match.answer;
-    if (isAnswer_) {
-      contents_ =
-          [CreateAnswerLine(match.answer->first_line(), isDarkTheme) retain];
-      description_ =
-          [CreateAnswerLine(match.answer->second_line(), isDarkTheme) retain];
-      maxLines_ = match.answer->second_line().num_text_lines();
-    } else {
-      contents_ = [CreateClassifiedAttributedString(
-          match.contents, ContentTextColor(isDarkTheme), match.contents_class,
-          isDarkTheme) retain];
-      if (!match.description.empty()) {
-        description_ = [CreateClassifiedAttributedString(
-            match.description, DimTextColor(isDarkTheme),
-            match.description_class, isDarkTheme) retain];
-      }
-    }
-  }
-  return self;
-}
-
-- (void)dealloc {
-  base::mac::ReleaseProperties(self);
-  [super dealloc];
-}
-
-- (instancetype)copyWithZone:(NSZone*)zone {
-  return [self retain];
-}
-
-- (CGFloat)getMatchContentsWidth {
-  return [contents_ size].width;
-}
-
-@end
-
-@implementation OmniboxPopupCell
-
-- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
-  OmniboxPopupMatrix* matrix =
-      base::mac::ObjCCastStrict<OmniboxPopupMatrix>(controlView);
-  BOOL isDarkTheme = [matrix hasDarkTheme];
-
-  if ([self state] == NSOnState || [self isHighlighted]) {
-    if ([self state] == NSOnState) {
-      [SelectedBackgroundColor(isDarkTheme) set];
-    } else {
-      [HoveredBackgroundColor(isDarkTheme) set];
-    }
-    NSRectFillUsingOperation(cellFrame, NSCompositeSourceOver);
-  }
-
-  [self drawMatchWithFrame:cellFrame inView:controlView];
-}
-
-- (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView {
-  OmniboxPopupCellData* cellData =
-      base::mac::ObjCCastStrict<OmniboxPopupCellData>([self objectValue]);
-  OmniboxPopupMatrix* tableView =
-      base::mac::ObjCCastStrict<OmniboxPopupMatrix>(controlView);
-  CGFloat remainingWidth =
-      [OmniboxPopupCell getTextContentAreaWidth:[tableView contentMaxWidth]];
-  CGFloat contentsWidth = [cellData getMatchContentsWidth];
-  CGFloat separatorWidth = [[tableView separator] size].width;
-  CGFloat descriptionWidth =
-      [cellData description] ? [[cellData description] size].width : 0;
-  int contentsMaxWidth, descriptionMaxWidth;
-  OmniboxPopupModel::ComputeMatchMaxWidths(
-      ceilf(contentsWidth), ceilf(separatorWidth), ceilf(descriptionWidth),
-      ceilf(remainingWidth), [cellData isAnswer],
-      !AutocompleteMatch::IsSearchType([cellData matchType]), &contentsMaxWidth,
-      &descriptionMaxWidth);
-
-  NSWindow* parentWindow = [[controlView window] parentWindow];
-  BOOL isDarkTheme = [parentWindow hasDarkTheme];
-  NSRect imageRect = cellFrame;
-  imageRect.size = [[cellData image] size];
-  imageRect.origin.x += kMaterialImageXOffset + [tableView contentLeftPadding];
-  imageRect.origin.y +=
-      GetVerticalMargin() + kMaterialExtraVerticalImagePadding;
-  [[cellData image] drawInRect:FlipIfRTL(imageRect, cellFrame)
-                      fromRect:NSZeroRect
-                     operation:NSCompositeSourceOver
-                      fraction:1.0
-                respectFlipped:YES
-                         hints:nil];
-
-  CGFloat left = kMaterialTextStartOffset + [tableView contentLeftPadding];
-  NSPoint origin = NSMakePoint(left, GetVerticalMargin());
-
-  origin.x += [self drawMatchPart:[cellData contents]
-                        withFrame:cellFrame
-                           origin:origin
-                     withMaxWidth:contentsMaxWidth
-                     forDarkTheme:isDarkTheme
-                    withHeightCap:true];
-
-  if (descriptionMaxWidth > 0) {
-    if ([cellData isAnswer]) {
-      origin = NSMakePoint(
-          left, [OmniboxPopupCell getContentTextHeight] - GetVerticalMargin());
-      CGFloat imageSize = [tableView answerLineHeight];
-      NSRect imageRect =
-          NSMakeRect(NSMinX(cellFrame) + origin.x, NSMinY(cellFrame) + origin.y,
-                     imageSize, imageSize);
-      [[cellData answerImage] drawInRect:FlipIfRTL(imageRect, cellFrame)
-                                fromRect:NSZeroRect
-                               operation:NSCompositeSourceOver
-                                fraction:1.0
-                          respectFlipped:YES
-                                   hints:nil];
-      if ([cellData answerImage]) {
-        origin.x += imageSize + kMaterialImageXOffset;
-
-        // Have to nudge the baseline down 1pt in Material Design for the text
-        // that follows, so that it's the same as the bottom of the image.
-        origin.y += 1;
-      }
-    } else {
-      origin.x += [self drawMatchPart:[tableView separator]
-                            withFrame:cellFrame
-                               origin:origin
-                         withMaxWidth:separatorWidth
-                         forDarkTheme:isDarkTheme
-                        withHeightCap:true];
-    }
-    [self drawMatchPart:[cellData description]
-              withFrame:cellFrame
-                 origin:origin
-           withMaxWidth:descriptionMaxWidth
-           forDarkTheme:isDarkTheme
-          withHeightCap:false];
-  }
-}
-
-- (CGFloat)drawMatchPart:(NSAttributedString*)attributedString
-               withFrame:(NSRect)cellFrame
-                  origin:(NSPoint)origin
-            withMaxWidth:(int)maxWidth
-            forDarkTheme:(BOOL)isDarkTheme
-           withHeightCap:(BOOL)hasHeightCap {
-  NSRect renderRect = NSIntersectionRect(
-      cellFrame, NSOffsetRect(cellFrame, origin.x, origin.y));
-  renderRect.size.width =
-      std::min(NSWidth(renderRect), static_cast<CGFloat>(maxWidth));
-  if (hasHeightCap)
-    renderRect.size.height =
-        std::min(NSHeight(renderRect), [attributedString size].height);
-  if (!NSIsEmptyRect(renderRect)) {
-    [attributedString drawWithRect:FlipIfRTL(renderRect, cellFrame)
-                           options:NSStringDrawingUsesLineFragmentOrigin |
-                                   NSStringDrawingTruncatesLastVisibleLine];
-  }
-  return NSWidth(renderRect);
-}
-
-+ (CGFloat)computeContentsOffset:(const AutocompleteMatch&)match {
-  const base::string16& inputText = base::UTF8ToUTF16(
-      match.GetAdditionalInfo(kACMatchPropertySuggestionText));
-  int contentsStartIndex = 0;
-  base::StringToInt(
-      match.GetAdditionalInfo(kACMatchPropertyContentsStartIndex),
-      &contentsStartIndex);
-  // Ignore invalid state.
-  if (!base::StartsWith(match.fill_into_edit, inputText,
-                        base::CompareCase::SENSITIVE) ||
-      !base::EndsWith(match.fill_into_edit, match.contents,
-                      base::CompareCase::SENSITIVE) ||
-      ((size_t)contentsStartIndex >= inputText.length())) {
-    return 0;
-  }
-  bool isContentsRTL = (base::i18n::RIGHT_TO_LEFT ==
-      base::i18n::GetFirstStrongCharacterDirection(match.contents));
-
-  // Color does not matter.
-  NSAttributedString* attributedString =
-      CreateAttributedString(inputText, DimTextColor(false));
-  base::scoped_nsobject<NSTextStorage> textStorage(
-      [[NSTextStorage alloc] initWithAttributedString:attributedString]);
-  base::scoped_nsobject<NSLayoutManager> layoutManager(
-      [[NSLayoutManager alloc] init]);
-  base::scoped_nsobject<NSTextContainer> textContainer(
-      [[NSTextContainer alloc] init]);
-  [layoutManager addTextContainer:textContainer];
-  [textStorage addLayoutManager:layoutManager];
-
-  NSUInteger charIndex = static_cast<NSUInteger>(contentsStartIndex);
-  NSUInteger glyphIndex =
-      [layoutManager glyphIndexForCharacterAtIndex:charIndex];
-
-  // This offset is computed from the left edge of the glyph always from the
-  // left edge of the string, irrespective of the directionality of UI or text.
-  CGFloat glyphOffset = [layoutManager locationForGlyphAtIndex:glyphIndex].x;
-
-  CGFloat inputWidth = [attributedString size].width;
-
-  // The offset obtained above may need to be corrected because the left-most
-  // glyph may not have 0 offset. So we find the offset of left-most glyph, and
-  // subtract it from the offset of the glyph we obtained above.
-  CGFloat minOffset = glyphOffset;
-
-  // If content is RTL, we are interested in the right-edge of the glyph.
-  // Unfortunately the bounding rect computation methods from NSLayoutManager or
-  // NSFont don't work correctly with bidirectional text. So we compute the
-  // glyph width by finding the closest glyph offset to the right of the glyph
-  // we are looking for.
-  CGFloat glyphWidth = inputWidth;
-
-  for (NSUInteger i = 0; i < [attributedString length]; i++) {
-    if (i == charIndex) continue;
-    glyphIndex = [layoutManager glyphIndexForCharacterAtIndex:i];
-    CGFloat offset = [layoutManager locationForGlyphAtIndex:glyphIndex].x;
-    minOffset = std::min(minOffset, offset);
-    if (offset > glyphOffset)
-      glyphWidth = std::min(glyphWidth, offset - glyphOffset);
-  }
-  glyphOffset -= minOffset;
-  if (glyphWidth == 0)
-    glyphWidth = inputWidth - glyphOffset;
-  if (isContentsRTL)
-    glyphOffset += glyphWidth;
-  return base::i18n::IsRTL() ? (inputWidth - glyphOffset) : glyphOffset;
-}
-
-+ (NSAttributedString*)createSeparatorStringForDarkTheme:(BOOL)isDarkTheme {
-  base::string16 raw_separator =
-      l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR);
-  return CreateAttributedString(raw_separator, DimTextColor(isDarkTheme));
-}
-
-+ (CGFloat)getTextContentAreaWidth:(CGFloat)cellContentMaxWidth {
-  return cellContentMaxWidth - kMaterialTextStartOffset;
-}
-
-+ (CGFloat)getContentTextHeight {
-  return kDefaultTextHeight + 2 * GetVerticalMargin();
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
deleted file mode 100644
index caea321..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
-
-#include <stddef.h>
-
-#include "base/json/json_reader.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "components/omnibox/browser/suggestion_answer.h"
-#import "testing/gtest_mac.h"
-
-namespace {
-
-class OmniboxPopupCellTest : public CocoaTest {
- public:
-  OmniboxPopupCellTest() {
-  }
-
-  void SetUp() override {
-    CocoaTest::SetUp();
-    control_.reset([[NSControl alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)]);
-    [control_ setCell:cell_];
-    [[test_window() contentView] addSubview:control_];
-  };
-
- protected:
-  base::scoped_nsobject<OmniboxPopupCellData> cellData_;
-  base::scoped_nsobject<OmniboxPopupCell> cell_;
-  base::scoped_nsobject<NSControl> control_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupCellTest);
-};
-
-TEST_VIEW(OmniboxPopupCellTest, control_);
-
-TEST_F(OmniboxPopupCellTest, Image) {
-  AutocompleteMatch match;
-  cellData_.reset([[OmniboxPopupCellData alloc]
-       initWithMatch:match
-               image:[NSImage imageNamed:NSImageNameInfo]
-         answerImage:nil
-        forDarkTheme:NO]);
-  [cell_ setObjectValue:cellData_];
-  [control_ display];
-}
-
-TEST_F(OmniboxPopupCellTest, Title) {
-  AutocompleteMatch match;
-  match.contents =
-      base::ASCIIToUTF16("The quick brown fox jumps over the lazy dog.");
-  cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match
-                                                        image:nil
-                                                  answerImage:nil
-                                                 forDarkTheme:NO]);
-  [cell_ setObjectValue:cellData_];
-  [control_ display];
-}
-
-TEST_F(OmniboxPopupCellTest, AnswerStyle) {
-  const char* weatherJson =
-      "{\"l\": [ {\"il\": {\"t\": [ {"
-      "\"t\": \"weather in pari&lt;b&gt;s&lt;/b&gt;\", \"tt\": 8} ]}}, {"
-      "\"il\": {\"at\": {\"t\": \"Thu\",\"tt\": 12}, "
-      "\"i\": {\"d\": \"//ssl.gstatic.com/onebox/weather/64/cloudy.png\","
-      "\"t\": 3}, \"t\": [ {\"t\": \"46\",\"tt\": 1}, {"
-      "\"t\": \"°F\",\"tt\": 3} ]}} ]}";
-  NSString* finalString = @"46°F Thu";
-
-  std::unique_ptr<base::Value> root(base::JSONReader::Read(weatherJson));
-  ASSERT_NE(root, nullptr);
-  base::DictionaryValue* dictionary;
-  root->GetAsDictionary(&dictionary);
-  ASSERT_NE(dictionary, nullptr);
-  SuggestionAnswer answer;
-  EXPECT_TRUE(SuggestionAnswer::ParseAnswer(dictionary,
-                                            base::ASCIIToUTF16("-1"), &answer));
-  AutocompleteMatch match;
-  match.answer = answer;
-  cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match
-                                                        image:nil
-                                                  answerImage:nil
-                                                 forDarkTheme:NO]);
-  EXPECT_NSEQ([[cellData_ description] string], finalString);
-  size_t length = [[[cellData_ description] string] length];
-  EXPECT_EQ(length, 8UL);
-  const NSRange checkValues[] = {{0, 2}, {2, 2}, {4, 4}};
-  NSDictionary* lastAttributes = nil;
-  for (const NSRange& value : checkValues) {
-    NSRange range;
-    NSDictionary* currentAttributes =
-        [[cellData_ description] attributesAtIndex:value.location
-                                    effectiveRange:&range];
-    EXPECT_TRUE(NSEqualRanges(value, range));
-    EXPECT_FALSE([currentAttributes isEqualToDictionary:lastAttributes]);
-    lastAttributes = currentAttributes;
-  }
-}
-
-TEST_F(OmniboxPopupCellTest, DefinitionAnswerStyle) {
-  const char* definitionJson =
-      "{\"l\":"
-        "["
-          "{\"il\":"
-            "{\"at\":"
-              "{\"t\":\"\u2022 /??s??SH????liz??m/\","
-               "\"tt\":8},"
-             "\"t\":"
-                "["
-                  "{\"t\":\"definition of socialism\","
-                   "\"tt\":8}"
-                "]"
-            "}"
-          "},"
-          "{\"il\":"
-            "{\"t\":"
-              "["
-                "{\"t\":\"a political and economic theory\","
-                 "\"tt\":8,"
-                 "\"ln\":3}"
-              "]"
-            "}"
-          "}"
-        "]"
-      "}";
-  NSString* finalString = @"a political and economic theory";
-
-  std::unique_ptr<base::Value> root(base::JSONReader::Read(definitionJson));
-  ASSERT_NE(root, nullptr);
-  base::DictionaryValue* dictionary;
-  root->GetAsDictionary(&dictionary);
-  ASSERT_NE(dictionary, nullptr);
-  SuggestionAnswer answer;
-  EXPECT_TRUE(SuggestionAnswer::ParseAnswer(dictionary,
-                                            base::ASCIIToUTF16("-1"), &answer));
-  AutocompleteMatch match;
-  match.answer = answer;
-  cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match
-                                                        image:nil
-                                                  answerImage:nil
-                                                 forDarkTheme:NO]);
-  EXPECT_NSEQ([[cellData_ description] string], finalString);
-  size_t length = [[[cellData_ description] string] length];
-  EXPECT_EQ(length, 31UL);
-  const NSRange checkValue = {0, 31};
-  NSDictionary* lastAttributes = nil;
-  NSRange range;
-  NSDictionary* currentAttributes =
-      [[cellData_ description] attributesAtIndex:checkValue.location
-                                  effectiveRange:&range];
-  EXPECT_TRUE(NSEqualRanges(checkValue, range));
-  EXPECT_FALSE([currentAttributes isEqualToDictionary:lastAttributes]);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h
deleted file mode 100644
index 413ad26..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_MATRIX_H_
-#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_MATRIX_H_
-
-#import <Cocoa/Cocoa.h>
-#include <stddef.h>
-
-#import "ui/base/cocoa/tracking_area.h"
-#include "ui/base/window_open_disposition.h"
-
-class AutocompleteResult;
-@class OmniboxPopupCell;
-@class OmniboxPopupMatrix;
-class OmniboxPopupViewMac;
-
-@interface OmniboxPopupTableController
-    : NSObject<NSTableViewDelegate, NSTableViewDataSource> {
- @private
-  base::scoped_nsobject<NSArray> array_;
-  NSInteger hoveredIndex_;
-};
-
-// Setup the information used by the NSTableView data source.
-- (instancetype)initWithMatchResults:(const AutocompleteResult&)result
-                           tableView:(OmniboxPopupMatrix*)tableView
-                           popupView:(const OmniboxPopupViewMac&)popupView
-                         answerImage:(NSImage*)answerImage;
-
-// Set the hovered highlight.
-- (void)setHighlightedRow:(NSInteger)rowIndex;
-
-// Sets a custom match icon.
-- (void)setMatchIcon:(NSImage*)icon forRow:(NSInteger)rowIndex;
-
-// Which row has the hovered highlight.
-- (NSInteger)highlightedRow;
-
-@end
-
-@interface OmniboxPopupTableController (TestingAPI)
-- (instancetype)initWithArray:(NSArray*)array;
-@end
-
-@class OmniboxPopupMatrix;
-
-class OmniboxPopupMatrixObserver {
- public:
-  // Called when the selection in the matrix changes.
-  virtual void OnMatrixRowSelected(OmniboxPopupMatrix* matrix, size_t row) = 0;
-
-  // Called when the user clicks on a row.
-  virtual void OnMatrixRowClicked(OmniboxPopupMatrix* matrix, size_t row) = 0;
-
-  // Called when the user middle clicks on a row.
-  virtual void OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix,
-                                        size_t row) = 0;
-};
-
-// Sets up a tracking area to implement hover by highlighting the cell the mouse
-// is over.
-@interface OmniboxPopupMatrix : NSTableView {
-  base::scoped_nsobject<OmniboxPopupTableController> matrixController_;
-  OmniboxPopupMatrixObserver* observer_;  // weak
-  ui::ScopedCrTrackingArea trackingArea_;
-  NSAttributedString* separator_;
-
-  // The width of widest match contents in a set of tail suggestions.
-  CGFloat maxMatchContentsWidth_;
-
-  CGFloat answerLineHeight_;
-
-  // Left margin padding for the content (i.e. icon and text) in a cell.
-  CGFloat contentLeftPadding_;
-
-  // Max width for the content in the cell.
-  CGFloat contentMaxWidth_;
-
-  // true if the OmniboxPopupMatrix should use the dark theme style.
-  BOOL hasDarkTheme_;
-}
-
-@property(retain, nonatomic) NSAttributedString* separator;
-@property(nonatomic) CGFloat maxMatchContentsWidth;
-@property(nonatomic) CGFloat answerLineHeight;
-@property(nonatomic) CGFloat contentLeftPadding;
-@property(nonatomic) CGFloat contentMaxWidth;
-@property(readonly, nonatomic) BOOL hasDarkTheme;
-
-// Create a zero-size matrix.
-- (instancetype)initWithObserver:(OmniboxPopupMatrixObserver*)observer
-                    forDarkTheme:(BOOL)isDarkTheme;
-
-// Sets the observer.
-- (void)setObserver:(OmniboxPopupMatrixObserver*)observer;
-
-// Return the currently highlighted row.  Returns -1 if no row is highlighted.
-- (NSInteger)highlightedRow;
-
-// Move the selection to |rowIndex|.
-- (void)selectRowIndex:(NSInteger)rowIndex;
-
-// Setup the NSTableView data source.
-- (void)setController:(OmniboxPopupTableController*)controller;
-
-// Sets a custom match icon.
-- (void)setMatchIcon:(NSImage*)icon forRow:(NSInteger)rowIndex;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_MATRIX_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
deleted file mode 100644
index fbaabd7b..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
+++ /dev/null
@@ -1,325 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h"
-
-#include "base/logging.h"
-#include "base/mac/foundation_util.h"
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h"
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-#include "components/omnibox/browser/autocomplete_result.h"
-
-namespace {
-
-// NSEvent -buttonNumber for middle mouse button.
-const NSInteger kMiddleButtonNumber = 2;
-
-}  // namespace
-
-@interface OmniboxPopupMatrix ()
-- (OmniboxPopupTableController*)controller;
-- (void)resetTrackingArea;
-- (void)highlightRowUnder:(NSEvent*)theEvent;
-- (BOOL)selectCellForEvent:(NSEvent*)theEvent;
-@end
-
-@implementation OmniboxPopupTableController
-
-- (instancetype)initWithMatchResults:(const AutocompleteResult&)result
-                           tableView:(OmniboxPopupMatrix*)tableView
-                           popupView:(const OmniboxPopupViewMac&)popupView
-                         answerImage:(NSImage*)answerImage {
-  base::scoped_nsobject<NSMutableArray> array([[NSMutableArray alloc] init]);
-  BOOL isDarkTheme = [tableView hasDarkTheme];
-  for (const AutocompleteMatch& match : result) {
-    base::scoped_nsobject<OmniboxPopupCellData> cellData(
-        [[OmniboxPopupCellData alloc]
-            initWithMatch:match
-                    image:popupView.ImageForMatch(match)
-              answerImage:(match.answer ? answerImage : nil)
-             forDarkTheme:isDarkTheme]);
-    [array addObject:cellData];
-  }
-
-  return [self initWithArray:array];
-}
-
-- (instancetype)initWithArray:(NSArray*)array {
-  if ((self = [super init])) {
-    hoveredIndex_ = -1;
-    array_.reset([array copy]);
-  }
-  return self;
-}
-
-- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView {
-  return [array_ count];
-}
-
-- (id)tableView:(NSTableView*)tableView
-    objectValueForTableColumn:(NSTableColumn*)tableColumn
-                          row:(NSInteger)rowIndex {
-  return [array_ objectAtIndex:rowIndex];
-}
-
-- (void)tableView:(NSTableView*)tableView
-    setObjectValue:(id)object
-    forTableColumn:(NSTableColumn*)tableColumn
-               row:(NSInteger)rowIndex {
-  NOTREACHED();
-}
-
-- (void)tableView:(NSTableView*)tableView
-    willDisplayCell:(id)cell
-     forTableColumn:(NSTableColumn*)tableColumn
-                row:(NSInteger)rowIndex {
-  OmniboxPopupCell* popupCell =
-      base::mac::ObjCCastStrict<OmniboxPopupCell>(cell);
-  [popupCell
-      setState:([tableView selectedRow] == rowIndex) ? NSOnState : NSOffState];
-  [popupCell highlight:(hoveredIndex_ == rowIndex)
-             withFrame:[tableView bounds]
-                inView:tableView];
-}
-
-- (NSInteger)highlightedRow {
-  return hoveredIndex_;
-}
-
-- (void)setHighlightedRow:(NSInteger)rowIndex {
-  hoveredIndex_ = rowIndex;
-}
-
-- (void)setMatchIcon:(NSImage*)icon forRow:(NSInteger)rowIndex {
-  OmniboxPopupCellData* cellData =
-      base::mac::ObjCCastStrict<OmniboxPopupCellData>(
-          [array_ objectAtIndex:rowIndex]);
-  [cellData setImage:icon];
-}
-
-- (CGFloat)tableView:(NSTableView*)tableView heightOfRow:(NSInteger)row {
-  BOOL isAnswer = [[array_ objectAtIndex:row] isAnswer];
-  CGFloat height = [OmniboxPopupCell getContentTextHeight];
-
-  if (isAnswer) {
-    OmniboxPopupMatrix* matrix =
-        base::mac::ObjCCastStrict<OmniboxPopupMatrix>(tableView);
-    NSRect rowRect = [tableView rectOfColumn:0];
-    OmniboxPopupCellData* cellData =
-        base::mac::ObjCCastStrict<OmniboxPopupCellData>(
-            [array_ objectAtIndex:row]);
-    // Subtract any Material Design padding and/or icon.
-    rowRect.size.width =
-        [OmniboxPopupCell getTextContentAreaWidth:[matrix contentMaxWidth]];
-    NSAttributedString* text = [cellData description];
-    // Provide no more than 3 lines of space.
-    rowRect.size.height =
-        std::min(3, [cellData maxLines]) * [text size].height;
-    NSRect textRect =
-        [text boundingRectWithSize:rowRect.size
-                           options:NSStringDrawingUsesLineFragmentOrigin |
-                                   NSStringDrawingTruncatesLastVisibleLine];
-    // Add a little padding or it looks cramped.
-    int heightProvided = textRect.size.height + 2;
-    height += heightProvided;
-  }
-  return height;
-}
-
-@end
-
-@implementation OmniboxPopupMatrix
-
-@synthesize separator = separator_;
-@synthesize maxMatchContentsWidth = maxMatchContentsWidth_;
-@synthesize contentLeftPadding = contentLeftPadding_;
-@synthesize contentMaxWidth = contentMaxWidth_;
-@synthesize answerLineHeight = answerLineHeight_;
-@synthesize hasDarkTheme = hasDarkTheme_;
-
-- (instancetype)initWithObserver:(OmniboxPopupMatrixObserver*)observer
-                    forDarkTheme:(BOOL)isDarkTheme {
-  if ((self = [super initWithFrame:NSZeroRect])) {
-    observer_ = observer;
-    hasDarkTheme_ = isDarkTheme;
-
-    base::scoped_nsobject<NSTableColumn> column(
-        [[NSTableColumn alloc] initWithIdentifier:@"MainColumn"]);
-    [column setDataCell:[[[OmniboxPopupCell alloc] init] autorelease]];
-    [self addTableColumn:column];
-
-    // Cells pack with no spacing.
-    [self setIntercellSpacing:NSMakeSize(0.0, 0.0)];
-
-    [self setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleNone];
-    NSColor* backgroundColor =
-        OmniboxPopupViewMac::BackgroundColor(hasDarkTheme_);
-    [self setBackgroundColor:backgroundColor];
-    [self setAllowsEmptySelection:YES];
-    [self deselectAll:self];
-
-    [self resetTrackingArea];
-
-    base::scoped_nsobject<NSLayoutManager> layoutManager(
-        [[NSLayoutManager alloc] init]);
-    answerLineHeight_ =
-        [layoutManager defaultLineHeightForFont:OmniboxViewMac::GetLargeFont()];
-  }
-  return self;
-}
-
-- (OmniboxPopupTableController*)controller {
-  return base::mac::ObjCCastStrict<OmniboxPopupTableController>(
-      [self delegate]);
-}
-
-- (void)setObserver:(OmniboxPopupMatrixObserver*)observer {
-  observer_ = observer;
-}
-
-- (void)updateTrackingAreas {
-  [self resetTrackingArea];
-  [super updateTrackingAreas];
-}
-
-// Callbacks from tracking area.
-- (void)mouseMoved:(NSEvent*)theEvent {
-  [self highlightRowUnder:theEvent];
-}
-
-- (void)mouseExited:(NSEvent*)theEvent {
-  [self highlightRowUnder:theEvent];
-}
-
-// The tracking area events aren't forwarded during a drag, so handle
-// highlighting manually for middle-click and middle-drag.
-- (void)otherMouseDown:(NSEvent*)theEvent {
-  if ([theEvent buttonNumber] == kMiddleButtonNumber) {
-    [self highlightRowUnder:theEvent];
-  }
-  [super otherMouseDown:theEvent];
-}
-
-- (void)otherMouseDragged:(NSEvent*)theEvent {
-  if ([theEvent buttonNumber] == kMiddleButtonNumber) {
-    [self highlightRowUnder:theEvent];
-  }
-  [super otherMouseDragged:theEvent];
-}
-
-- (void)otherMouseUp:(NSEvent*)theEvent {
-  // Only intercept middle button.
-  if ([theEvent buttonNumber] != kMiddleButtonNumber) {
-    [super otherMouseUp:theEvent];
-    return;
-  }
-
-  // -otherMouseDragged: should always have been called at this location, but
-  // make sure the user is getting the right feedback.
-  [self highlightRowUnder:theEvent];
-
-  const NSInteger highlightedRow = [[self controller] highlightedRow];
-  if (highlightedRow != -1) {
-    DCHECK(observer_);
-    observer_->OnMatrixRowMiddleClicked(self, highlightedRow);
-  }
-}
-
-// Track the mouse until released, keeping the cell under the mouse selected.
-// If the mouse wanders off-view, revert to the originally-selected cell. If
-// the mouse is released over a cell, call the delegate to open the row's URL.
-- (void)mouseDown:(NSEvent*)theEvent {
-  NSCell* selectedCell = [self selectedCell];
-
-  // Clear any existing highlight.
-  [[self controller] setHighlightedRow:-1];
-
-  do {
-    if (![self selectCellForEvent:theEvent]) {
-      [self selectCell:selectedCell];
-    }
-
-    const NSUInteger mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
-    theEvent = [[self window] nextEventMatchingMask:mask];
-  } while ([theEvent type] == NSLeftMouseDragged);
-
-  // Do not message the delegate if released outside view.
-  if (![self selectCellForEvent:theEvent]) {
-    [self selectCell:selectedCell];
-  } else {
-    const NSInteger selectedRow = [self selectedRow];
-
-    // No row could be selected if the model failed to update.
-    if (selectedRow == -1) {
-      NOTREACHED();
-      return;
-    }
-
-    DCHECK(observer_);
-    observer_->OnMatrixRowClicked(self, selectedRow);
-  }
-}
-
-- (void)selectRowIndex:(NSInteger)rowIndex {
-  NSIndexSet* indexSet = [NSIndexSet indexSetWithIndex:rowIndex];
-  [self selectRowIndexes:indexSet byExtendingSelection:NO];
-}
-
-- (NSInteger)highlightedRow {
-  return [[self controller] highlightedRow];
-}
-
-- (void)setController:(OmniboxPopupTableController*)controller {
-  matrixController_.reset([controller retain]);
-  [self setDelegate:controller];
-  [self setDataSource:controller];
-  [self reloadData];
-}
-
-- (void)resetTrackingArea {
-  if (trackingArea_.get())
-    [self removeTrackingArea:trackingArea_.get()];
-
-  trackingArea_.reset([[CrTrackingArea alloc]
-      initWithRect:[self frame]
-           options:NSTrackingMouseEnteredAndExited |
-                   NSTrackingMouseMoved |
-                   NSTrackingActiveInActiveApp |
-                   NSTrackingInVisibleRect
-             owner:self
-          userInfo:nil]);
-  [self addTrackingArea:trackingArea_.get()];
-}
-
-- (void)highlightRowUnder:(NSEvent*)theEvent {
-  NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
-  NSInteger oldRow = [[self controller] highlightedRow];
-  NSInteger newRow = [self rowAtPoint:point];
-  if (oldRow != newRow) {
-    [[self controller] setHighlightedRow:newRow];
-    [self setNeedsDisplayInRect:[self rectOfRow:oldRow]];
-    [self setNeedsDisplayInRect:[self rectOfRow:newRow]];
-  }
-}
-
-- (BOOL)selectCellForEvent:(NSEvent*)theEvent {
-  NSPoint point = [self convertPoint:[theEvent locationInWindow] fromView:nil];
-
-  NSInteger row = [self rowAtPoint:point];
-  [self selectRowIndex:row];
-  if (row != -1) {
-    DCHECK(observer_);
-    observer_->OnMatrixRowSelected(self, row);
-    return YES;
-  }
-  return NO;
-}
-
-- (void)setMatchIcon:(NSImage*)icon forRow:(NSInteger)rowIndex {
-  [[self controller] setMatchIcon:icon forRow:rowIndex];
-  [self setNeedsDisplayInRect:[self rectOfRow:rowIndex]];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm
deleted file mode 100644
index 616a638..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h"
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#import "ui/events/test/cocoa_test_event_utils.h"
-
-namespace {
-
-NSEvent* MouseEventInRow(OmniboxPopupMatrix* matrix,
-                         NSEventType type,
-                         NSInteger row) {
-  NSRect cell_rect = [matrix rectOfRow:row];
-  NSPoint point_in_view = NSMakePoint(NSMidX(cell_rect), NSMidY(cell_rect));
-  NSPoint point_in_window = [matrix convertPoint:point_in_view toView:nil];
-  return cocoa_test_event_utils::MouseEventAtPoint(
-      point_in_window, type, 0);
-}
-
-class OmniboxPopupMatrixTest : public CocoaTest,
-                               public OmniboxPopupMatrixObserver {
- public:
-  OmniboxPopupMatrixTest()
-      : selected_row_(0), clicked_row_(0), middle_clicked_row_(0) {}
-
-  void SetUp() override {
-    CocoaTest::SetUp();
-    matrix_.reset([[OmniboxPopupMatrix alloc] initWithObserver:this
-                                                  forDarkTheme:NO]);
-    [[test_window() contentView] addSubview:matrix_];
-
-    NSMutableArray* array = [NSMutableArray array];
-    for (size_t i = 0; i < 3; ++i)
-      [array addObject:[[[OmniboxPopupCellData alloc] init] autorelease]];
-
-    matrixController_.reset(
-        [[OmniboxPopupTableController alloc] initWithArray:array]);
-    [matrix_ setController:matrixController_];
-  };
-
-  void OnMatrixRowSelected(OmniboxPopupMatrix* matrix, size_t row) override {
-    selected_row_ = row;
-  }
-
-  void OnMatrixRowClicked(OmniboxPopupMatrix* matrix, size_t row) override {
-    clicked_row_ = row;
-  }
-
-  void OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix,
-                                size_t row) override {
-    middle_clicked_row_ = row;
-  }
-
- protected:
-  base::scoped_nsobject<OmniboxPopupMatrix> matrix_;
-  base::scoped_nsobject<OmniboxPopupTableController> matrixController_;
-  size_t selected_row_;
-  size_t clicked_row_;
-  size_t middle_clicked_row_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupMatrixTest);
-};
-
-TEST_VIEW(OmniboxPopupMatrixTest, matrix_);
-
-TEST_F(OmniboxPopupMatrixTest, HighlightedRow) {
-  EXPECT_EQ(-1, [matrix_ highlightedRow]);
-
-  [matrix_ mouseMoved:MouseEventInRow(matrix_, NSMouseMoved, 0)];
-  EXPECT_EQ(0, [matrix_ highlightedRow]);
-  [matrix_ mouseMoved:MouseEventInRow(matrix_, NSMouseMoved, 2)];
-  EXPECT_EQ(2, [matrix_ highlightedRow]);
-
-  [matrix_ mouseExited:cocoa_test_event_utils::MouseEventAtPoint(
-                           NSZeroPoint, NSMouseMoved, 0)];
-  EXPECT_EQ(-1, [matrix_ highlightedRow]);
-}
-
-TEST_F(OmniboxPopupMatrixTest, SelectedRow) {
-  [NSApp postEvent:MouseEventInRow(matrix_, NSLeftMouseUp, 2) atStart:YES];
-  [matrix_ mouseDown:MouseEventInRow(matrix_, NSLeftMouseDown, 2)];
-
-  EXPECT_EQ(2u, selected_row_);
-  EXPECT_EQ(2u, clicked_row_);
-  EXPECT_EQ(0u, middle_clicked_row_);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h
deleted file mode 100644
index 1b91be76..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_SEPARATOR_VIEW_H_
-#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_SEPARATOR_VIEW_H_
-
-#import <Cocoa/Cocoa.h>
-
-#include "chrome/browser/ui/cocoa/background_gradient_view.h"
-
-// A view used to draw a separator above omnibox popup.
-@interface OmniboxPopupTopSeparatorView : BackgroundGradientView {
-}
-
-+ (CGFloat)preferredHeight;
-
-@end
-
-// A view used to draw a drop shadow beneath the omnibox popup.
-@interface OmniboxPopupBottomSeparatorView : NSView {
- @private
-  BOOL isDarkTheme_;
-}
-
-+ (CGFloat)preferredHeight;
-- (instancetype)initWithFrame:(NSRect)frame forDarkTheme:(BOOL)isDarkTheme;
-
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_SEPARATOR_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.mm
deleted file mode 100644
index f763108..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.mm
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h"
-
-#import "base/mac/scoped_nsobject.h"
-#include "chrome/grit/theme_resources.h"
-#import "ui/base/cocoa/nsview_additions.h"
-#include "ui/base/resource/resource_bundle.h"
-
-@implementation OmniboxPopupTopSeparatorView
-
-+ (CGFloat)preferredHeight {
-  return 1;
-}
-
-- (void)drawRect:(NSRect)rect {
-  NSRect separatorRect = [self bounds];
-  separatorRect.size.height = [self cr_lineWidth];
-  [[self strokeColor] set];
-  NSRectFillUsingOperation(separatorRect, NSCompositeSourceOver);
-}
-
-@end
-
-@implementation OmniboxPopupBottomSeparatorView
-
-+ (CGFloat)preferredHeight {
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  NSImage* shadowImage =
-      rb.GetNativeImageNamed(IDR_OVERLAY_DROP_SHADOW).ToNSImage();
-  return [shadowImage size].height;
-}
-
-- (instancetype)initWithFrame:(NSRect)frame forDarkTheme:(BOOL)isDarkTheme {
-  if ((self = [self initWithFrame:frame])) {
-    isDarkTheme_ = isDarkTheme;
-    // For dark themes the OmniboxPopupBottomSeparatorView will render a shadow
-    // rather than blit a bitmap. Shadows are expensive to draw so use a layer
-    // to cache the result.
-    if (isDarkTheme_) {
-      [self setWantsLayer:YES];
-    }
-  }
-  return self;
-}
-
-- (void)drawRect:(NSRect)rect {
-  NSRect bounds = [self bounds];
-
-  if (isDarkTheme_) {
-    // There's an image for the shadow the Omnibox casts, but this shadow is
-    // an opaque mix of white and black, which makes it look strange against a
-    // dark NTP page. For dark mode, draw the shadow in code instead so that
-    // it has some transparency.
-    base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
-    [shadow setShadowBlurRadius:8];
-    [shadow setShadowColor:[NSColor blackColor]];
-    [shadow set];
-
-    // Fill a rect that's out of view to get just the shadow it casts.
-    [[NSColor blackColor] set];
-    NSRectFill(NSMakeRect(-3, NSMaxY(bounds), NSWidth(bounds) + 6, 5));
-    return;
-  }
-
-  // Draw the shadow.
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  NSImage* shadowImage =
-      rb.GetNativeImageNamed(IDR_OVERLAY_DROP_SHADOW).ToNSImage();
-  [shadowImage drawInRect:bounds
-                 fromRect:NSZeroRect
-                operation:NSCompositeSourceOver
-                 fraction:1.0];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm
deleted file mode 100644
index 1c7e18c..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h"
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-
-class OmniboxPopupBottomSeparatorViewTest : public CocoaTest {
- public:
-  OmniboxPopupBottomSeparatorViewTest() {
-    NSView* contentView = [test_window() contentView];
-    bottom_view_.reset([[OmniboxPopupBottomSeparatorView alloc]
-        initWithFrame:[contentView bounds]]);
-    [contentView addSubview:bottom_view_];
-  }
-
- protected:
-  base::scoped_nsobject<OmniboxPopupBottomSeparatorView> bottom_view_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupBottomSeparatorViewTest);
-};
-
-TEST_VIEW(OmniboxPopupBottomSeparatorViewTest, bottom_view_);
-
-TEST_F(OmniboxPopupBottomSeparatorViewTest, PreferredHeight) {
-  EXPECT_LT(0, [OmniboxPopupBottomSeparatorView preferredHeight]);
-}
-
-class OmniboxPopupTopSeparatorViewTest : public CocoaTest {
- public:
-  OmniboxPopupTopSeparatorViewTest() {
-    NSView* contentView = [test_window() contentView];
-    top_view_.reset([[OmniboxPopupTopSeparatorView alloc]
-        initWithFrame:[contentView bounds]]);
-    [contentView addSubview:top_view_];
-  }
-
- protected:
-  base::scoped_nsobject<OmniboxPopupTopSeparatorView> top_view_;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupTopSeparatorViewTest);
-};
-
-TEST_VIEW(OmniboxPopupTopSeparatorViewTest, top_view_);
-
-TEST_F(OmniboxPopupTopSeparatorViewTest, PreferredHeight) {
-  EXPECT_LT(0, [OmniboxPopupTopSeparatorView preferredHeight]);
-}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
deleted file mode 100644
index cba9c9b..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_VIEW_MAC_H_
-#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_VIEW_MAC_H_
-
-#import <Cocoa/Cocoa.h>
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.h"
-#include "components/omnibox/browser/autocomplete_match.h"
-#include "components/omnibox/browser/omnibox_popup_view.h"
-#include "ui/gfx/font.h"
-
-class AutocompleteResult;
-class OmniboxEditModel;
-class OmniboxPopupModel;
-class OmniboxView;
-
-// Implements OmniboxPopupView using a raw NSWindow containing an
-// NSTableView.
-class OmniboxPopupViewMac : public OmniboxPopupView,
-                            public OmniboxPopupMatrixObserver {
- public:
-  OmniboxPopupViewMac(OmniboxView* omnibox_view,
-                      OmniboxEditModel* edit_model,
-                      NSTextField* field);
-  ~OmniboxPopupViewMac() override;
-
-  // Return the OmniboxPopupViewMac background color.
-  static NSColor* BackgroundColor(bool is_dark_theme);
-
-  // Overridden from OmniboxPopupView:
-  bool IsOpen() const override;
-  void InvalidateLine(size_t line) override {}
-  void OnLineSelected(size_t line) override {}
-  void UpdatePopupAppearance() override;
-  void OnMatchIconUpdated(size_t match_index) override;
-  // This is only called by model in SetSelectedLine() after updating
-  // everything.  Popup should already be visible.
-  void PaintUpdatesNow() override;
-  void OnDragCanceled() override {}
-
-  // Overridden from OmniboxPopupMatrixDelegate:
-  void OnMatrixRowSelected(OmniboxPopupMatrix* matrix, size_t row) override;
-  void OnMatrixRowClicked(OmniboxPopupMatrix* matrix, size_t row) override;
-  void OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix,
-                                size_t row) override;
-
-  // Returns the NSImage that should be used as an icon for the given match.
-  NSImage* ImageForMatch(const AutocompleteMatch& match) const;
-
-  OmniboxPopupMatrix* matrix() { return matrix_; }
-
- protected:
-  // Gets the autocomplete results. This is virtual so that it can be overridden
-  // by tests.
-  virtual const AutocompleteResult& GetResult() const;
-
- private:
-  // Create the popup_ instance if needed.
-  void CreatePopupIfNeeded();
-
-  // Calculate the appropriate position for the popup based on the
-  // field's screen position and the given target for the matrix
-  // height, and makes the popup visible.  Animates to the new frame
-  // if the popup shrinks, snaps to the new frame if the popup grows,
-  // allows existing animations to continue if the size doesn't
-  // change.
-  void PositionPopup(const CGFloat matrixHeight);
-
-  // Opens the URL at the given row.
-  void OpenURLForRow(size_t row, WindowOpenDisposition disposition);
-
-  OmniboxView* omnibox_view_;
-  std::unique_ptr<OmniboxPopupModel> model_;
-  NSTextField* field_;  // owned by tab controller
-
-  // Child window containing a matrix which implements the popup.
-  base::scoped_nsobject<NSWindow> popup_;
-
-  base::scoped_nsobject<OmniboxPopupMatrix> matrix_;
-  base::scoped_nsobject<NSView> top_separator_view_;
-  base::scoped_nsobject<NSView> bottom_separator_view_;
-  base::scoped_nsobject<NSBox> background_view_;
-
-  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupViewMac);
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_POPUP_VIEW_MAC_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
deleted file mode 100644
index 8a19238d0..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
+++ /dev/null
@@ -1,335 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h"
-
-#include <cmath>
-
-#include "base/mac/mac_util.h"
-#import "base/mac/sdk_forward_declarations.h"
-#include "base/stl_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h"
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_separator_view.h"
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-#include "components/omnibox/browser/autocomplete_match.h"
-#include "components/omnibox/browser/autocomplete_match_type.h"
-#include "components/omnibox/browser/omnibox_edit_model.h"
-#include "components/omnibox/browser/omnibox_popup_model.h"
-#include "components/toolbar/vector_icons.h"
-#include "skia/ext/skia_utils_mac.h"
-#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h"
-#import "ui/base/cocoa/cocoa_base_utils.h"
-#import "ui/base/cocoa/flipped_view.h"
-#include "ui/base/cocoa/window_size_constants.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/image_skia_util_mac.h"
-#include "ui/gfx/paint_vector_icon.h"
-#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
-#include "ui/gfx/text_elider.h"
-
-namespace {
-
-const int kMaterialPopupPaddingVertical = 4;
-
-// Padding between matrix and the top and bottom of the popup window.
-CGFloat PopupPaddingVertical() {
-  return kMaterialPopupPaddingVertical;
-}
-
-// Animation duration when animating the popup window smaller.
-const NSTimeInterval kShrinkAnimationDuration = 0.1;
-
-}  // namespace
-
-OmniboxPopupViewMac::OmniboxPopupViewMac(OmniboxView* omnibox_view,
-                                         OmniboxEditModel* edit_model,
-                                         NSTextField* field)
-    : omnibox_view_(omnibox_view),
-      model_(new OmniboxPopupModel(this, edit_model)),
-      field_(field),
-      popup_(nil) {
-  DCHECK(omnibox_view);
-  DCHECK(edit_model);
-}
-
-OmniboxPopupViewMac::~OmniboxPopupViewMac() {
-  // Destroy the popup model before this object is destroyed, because
-  // it can call back to us in the destructor.
-  model_.reset();
-
-  // Break references to |this| because the popup may not be
-  // deallocated immediately.
-  [matrix_ setObserver:NULL];
-}
-
-// Background colors for different states of the popup elements.
-// static
-NSColor* OmniboxPopupViewMac::BackgroundColor(bool is_dark_theme) {
-  const CGFloat kMDDarkControlBackground = 40 / 255.;
-  return is_dark_theme
-             ? [NSColor colorWithGenericGamma22White:kMDDarkControlBackground
-                                               alpha:1]
-             : [NSColor controlBackgroundColor];
-}
-
-bool OmniboxPopupViewMac::IsOpen() const {
-  return popup_ != nil;
-}
-
-void OmniboxPopupViewMac::UpdatePopupAppearance() {
-  DCHECK([NSThread isMainThread]);
-  model_->autocomplete_controller()->InlineTailPrefixes();
-  const AutocompleteResult& result = GetResult();
-  const size_t rows = result.size();
-  if (rows == 0) {
-    [[popup_ parentWindow] removeChildWindow:popup_];
-    [popup_ orderOut:nil];
-
-    // Break references to |this| because the popup may not be
-    // deallocated immediately.
-    [matrix_ setObserver:NULL];
-    matrix_.reset();
-
-    popup_.reset(nil);
-    return;
-  }
-
-  CreatePopupIfNeeded();
-
-  NSImage* answerImage = nil;
-  const size_t result_size = model_->result().size();
-  for (size_t i = 0; i < result_size; ++i) {
-    const SkBitmap* bitmap = model_->RichSuggestionBitmapAt(i);
-    if (result.match_at(i).answer && bitmap != nullptr) {
-      answerImage = gfx::Image::CreateFrom1xBitmap(*bitmap).CopyNSImage();
-      break;
-    }
-  }
-  [matrix_ setController:[[[OmniboxPopupTableController alloc]
-                             initWithMatchResults:result
-                                        tableView:matrix_
-                                        popupView:*this
-                                      answerImage:answerImage] autorelease]];
-  BOOL is_dark_theme = [matrix_ hasDarkTheme];
-  [matrix_ setSeparator:[OmniboxPopupCell
-                            createSeparatorStringForDarkTheme:is_dark_theme]];
-
-  // Update the selection before placing (and displaying) the window.
-  PaintUpdatesNow();
-
-  // Calculate the matrix size manually rather than using -sizeToCells
-  // because actually resizing the matrix messed up the popup size
-  // animation.
-  DCHECK_EQ([matrix_ intercellSpacing].height, 0.0);
-  PositionPopup(NSHeight([matrix_ frame]));
-}
-
-void OmniboxPopupViewMac::OnMatchIconUpdated(size_t match_index) {
-  [matrix_ setMatchIcon:ImageForMatch(GetResult().match_at(match_index))
-                 forRow:match_index];
-}
-
-// This is only called by model in SetSelectedLine() after updating
-// everything.  Popup should already be visible.
-void OmniboxPopupViewMac::PaintUpdatesNow() {
-  [matrix_ selectRowIndex:model_->selected_line()];
-}
-
-void OmniboxPopupViewMac::OnMatrixRowSelected(OmniboxPopupMatrix* matrix,
-                                              size_t row) {
-  model_->SetSelectedLine(row, false, false);
-}
-
-void OmniboxPopupViewMac::OnMatrixRowClicked(OmniboxPopupMatrix* matrix,
-                                             size_t row) {
-  OpenURLForRow(row,
-                ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]));
-}
-
-void OmniboxPopupViewMac::OnMatrixRowMiddleClicked(OmniboxPopupMatrix* matrix,
-                                                   size_t row) {
-  OpenURLForRow(row, WindowOpenDisposition::NEW_BACKGROUND_TAB);
-}
-
-const AutocompleteResult& OmniboxPopupViewMac::GetResult() const {
-  return model_->result();
-}
-
-void OmniboxPopupViewMac::CreatePopupIfNeeded() {
-  if (!popup_) {
-    popup_.reset(
-        [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater
-                                    styleMask:NSBorderlessWindowMask
-                                      backing:NSBackingStoreBuffered
-                                        defer:NO]);
-    [popup_ setBackgroundColor:[NSColor clearColor]];
-    [popup_ setOpaque:NO];
-
-    // Use a flipped view to pin the matrix top the top left. This is needed
-    // for animated resize.
-    base::scoped_nsobject<FlippedView> contentView(
-        [[FlippedView alloc] initWithFrame:NSZeroRect]);
-    [popup_ setContentView:contentView];
-
-    BOOL is_dark_theme = [[field_ window] hasDarkTheme];
-
-    // View to draw a background beneath the matrix.
-    background_view_.reset([[NSBox alloc] initWithFrame:NSZeroRect]);
-    [background_view_ setBoxType:NSBoxCustom];
-    [background_view_ setBorderType:NSNoBorder];
-    [background_view_ setFillColor:BackgroundColor(is_dark_theme)];
-    [background_view_ setContentViewMargins:NSZeroSize];
-    [contentView addSubview:background_view_];
-
-    matrix_.reset([[OmniboxPopupMatrix alloc] initWithObserver:this
-                                                  forDarkTheme:is_dark_theme]);
-    [background_view_ addSubview:matrix_];
-
-    top_separator_view_.reset(
-        [[OmniboxPopupTopSeparatorView alloc] initWithFrame:NSZeroRect]);
-    [contentView addSubview:top_separator_view_];
-
-    bottom_separator_view_.reset([[OmniboxPopupBottomSeparatorView alloc]
-        initWithFrame:NSZeroRect
-         forDarkTheme:is_dark_theme]);
-    [contentView addSubview:bottom_separator_view_];
-
-    // TODO(dtseng): Ignore until we provide NSAccessibility support.
-    [popup_ accessibilitySetOverrideValue:NSAccessibilityUnknownRole
-                             forAttribute:NSAccessibilityRoleAttribute];
-  }
-}
-
-void OmniboxPopupViewMac::PositionPopup(const CGFloat matrixHeight) {
-  BrowserWindowController* controller =
-      [BrowserWindowController browserWindowControllerForView:field_];
-  NSRect anchor_rect_base = [controller omniboxPopupAnchorRect];
-
-  // Calculate the popup's position on the screen.
-  NSRect popup_frame = anchor_rect_base;
-
-  CGFloat table_width = NSWidth([[[field_ window] contentView] bounds]);
-  DCHECK_GT(table_width, 0.0);
-
-  NSPoint field_origin_base =
-      [field_ convertPoint:[field_ bounds].origin toView:nil];
-
-  // Size to fit the matrix and shift down by the size.
-  popup_frame.size.height = matrixHeight + PopupPaddingVertical() * 2.0;
-  popup_frame.size.height += [OmniboxPopupTopSeparatorView preferredHeight];
-  popup_frame.size.height += [OmniboxPopupBottomSeparatorView preferredHeight];
-  popup_frame.origin.x = 0;
-  popup_frame.origin.y -= NSHeight(popup_frame);
-
-  // Shift to screen coordinates.
-  if ([controller window]) {
-    popup_frame = [[controller window] convertRectToScreen:popup_frame];
-  }
-
-  // Top separator.
-  NSRect top_separator_frame = NSZeroRect;
-  top_separator_frame.size.width = NSWidth(popup_frame);
-  top_separator_frame.size.height =
-      [OmniboxPopupTopSeparatorView preferredHeight];
-  [top_separator_view_ setFrame:top_separator_frame];
-
-  // Bottom separator.
-  NSRect bottom_separator_frame = NSZeroRect;
-  bottom_separator_frame.size.width = NSWidth(popup_frame);
-  bottom_separator_frame.size.height =
-      [OmniboxPopupBottomSeparatorView preferredHeight];
-  bottom_separator_frame.origin.y =
-      NSHeight(popup_frame) - NSHeight(bottom_separator_frame);
-  [bottom_separator_view_ setFrame:bottom_separator_frame];
-
-  // Background view.
-  NSRect background_rect = NSZeroRect;
-  background_rect.size.width = NSWidth(popup_frame);
-  background_rect.size.height = NSHeight(popup_frame) -
-      NSHeight(top_separator_frame) - NSHeight(bottom_separator_frame);
-  background_rect.origin.y = NSMaxY(top_separator_frame);
-  [background_view_ setFrame:background_rect];
-
-  // Matrix.
-  NSRect matrix_frame = NSZeroRect;
-  matrix_frame.origin.x = 0;
-  [matrix_ setContentLeftPadding:field_origin_base.x];
-  [matrix_ setContentMaxWidth:NSWidth([field_ bounds])];
-  matrix_frame.origin.y = PopupPaddingVertical();
-  matrix_frame.size.width = table_width;
-  matrix_frame.size.height = matrixHeight;
-  [matrix_ setFrame:matrix_frame];
-  [[[matrix_ tableColumns] objectAtIndex:0] setWidth:table_width];
-
-  // Don't play animation games on first display.
-  if (![popup_ parentWindow]) {
-    DCHECK(![popup_ isVisible]);
-    [popup_ setFrame:popup_frame display:NO];
-    [[field_ window] addChildWindow:popup_ ordered:NSWindowAbove];
-    return;
-  }
-  DCHECK([popup_ isVisible]);
-
-  // Animate the frame change if the only change is that the height got smaller.
-  // Otherwise, resize immediately.
-  NSRect current_popup_frame = [popup_ frame];
-  bool animate = (NSHeight(popup_frame) < NSHeight(current_popup_frame) &&
-                  NSWidth(popup_frame) == NSWidth(current_popup_frame));
-
-  base::scoped_nsobject<NSDictionary> savedAnimations;
-  if (!animate) {
-    // In an ideal world, running a zero-length animation would cancel any
-    // running animations and set the new frame value immediately.  In practice,
-    // zero-length animations are ignored entirely.  Work around this AppKit bug
-    // by explicitly setting an NSNull animation for the "frame" key and then
-    // running the animation with a non-zero(!!) duration.  This somehow
-    // convinces AppKit to do the right thing.  Save off the current animations
-    // dictionary so it can be restored later.
-    savedAnimations.reset([[popup_ animations] copy]);
-    [popup_ setAnimations:@{@"frame" : [NSNull null]}];
-  }
-
-  [NSAnimationContext beginGrouping];
-  // Don't use the GTM addition for the "Steve" slowdown because this can
-  // happen async from user actions and the effects could be a surprise.
-  [[NSAnimationContext currentContext] setDuration:kShrinkAnimationDuration];
-  // When using the animator to update |popup_| on El Capitan, for some reason
-  // the window does not get redrawn. Use a completion handler to make sure
-  // |popup_| gets redrawn once the animation completes. See
-  // http://crbug.com/538590 and http://crbug.com/551007 .
-  if (base::mac::IsAtLeastOS10_11()) {
-    NSWindow* popup = popup_.get();
-    [[NSAnimationContext currentContext] setCompletionHandler:^{
-      [popup display];
-    }];
-  }
-  [[popup_ animator] setFrame:popup_frame display:YES];
-  [NSAnimationContext endGrouping];
-
-  if (!animate) {
-    // Restore the original animations dictionary.  This does not reinstate any
-    // previously running animations.
-    [popup_ setAnimations:savedAnimations];
-  }
-}
-
-NSImage* OmniboxPopupViewMac::ImageForMatch(
-    const AutocompleteMatch& match) const {
-  bool is_dark_mode = [matrix_ hasDarkTheme];
-  const SkColor vector_icon_color =
-      is_dark_mode ? SkColorSetA(SK_ColorWHITE, 0xCC) : gfx::kChromeIconGrey;
-  return model_->GetMatchIcon(match, vector_icon_color).ToNSImage();
-}
-
-void OmniboxPopupViewMac::OpenURLForRow(size_t row,
-                                        WindowOpenDisposition disposition) {
-  DCHECK_LT(row, GetResult().size());
-  omnibox_view_->OpenMatch(GetResult().match_at(row), disposition, GURL(),
-                           base::string16(), row, base::TimeTicks());
-}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
deleted file mode 100644
index e81c00c..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h"
-
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/omnibox/browser/autocomplete_input.h"
-#include "components/omnibox/browser/autocomplete_result.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/text_elider.h"
-
-namespace {
-
-class MockOmniboxPopupViewMac : public OmniboxPopupViewMac {
- public:
-  MockOmniboxPopupViewMac(OmniboxView* omnibox_view,
-                          OmniboxEditModel* edit_model,
-                          NSTextField* field)
-      : OmniboxPopupViewMac(omnibox_view, edit_model, field) {
-  }
-
-  void SetResultCount(size_t count) {
-    ACMatches matches;
-    for (size_t i = 0; i < count; ++i)
-      matches.push_back(AutocompleteMatch());
-    result_.Reset();
-    result_.AppendMatches(AutocompleteInput(), matches);
-  }
-
- protected:
-  const AutocompleteResult& GetResult() const override { return result_; }
-
- private:
-  AutocompleteResult result_;
-};
-
-class OmniboxPopupViewMacTest : public CocoaProfileTest {
- public:
-  OmniboxPopupViewMacTest() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(OmniboxPopupViewMacTest);
-};
-
-TEST_F(OmniboxPopupViewMacTest, UpdatePopupAppearance) {
-  base::scoped_nsobject<NSTextField> field(
-      [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 20)]);
-  [[test_window() contentView] addSubview:field];
-
-  OmniboxViewMac view(NULL, profile(), NULL, NULL);
-  MockOmniboxPopupViewMac popup_view(&view, view.model(), field);
-
-  popup_view.UpdatePopupAppearance();
-  EXPECT_FALSE(popup_view.IsOpen());
-  EXPECT_EQ(0, [popup_view.matrix() numberOfRows]);
-
-  popup_view.SetResultCount(3);
-  popup_view.UpdatePopupAppearance();
-  EXPECT_TRUE(popup_view.IsOpen());
-  EXPECT_EQ(3, [popup_view.matrix() numberOfRows]);
-
-  popup_view.SetResultCount(5);
-  popup_view.UpdatePopupAppearance();
-  EXPECT_EQ(5, [popup_view.matrix() numberOfRows]);
-
-  popup_view.SetResultCount(0);
-  popup_view.UpdatePopupAppearance();
-  EXPECT_FALSE(popup_view.IsOpen());
-  EXPECT_EQ(0, [popup_view.matrix() numberOfRows]);
-}
-
-}  // namespace
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
deleted file mode 100644
index 222d8dd..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h
+++ /dev/null
@@ -1,246 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_VIEW_MAC_H_
-#define CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_VIEW_MAC_H_
-
-#import <Cocoa/Cocoa.h>
-#include <stddef.h>
-
-#include <memory>
-
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
-#include "components/omnibox/browser/omnibox_view.h"
-#include "components/security_state/core/security_state.h"
-#include "third_party/skia/include/core/SkColor.h"
-
-class CommandUpdater;
-class OmniboxPopupView;
-class Profile;
-
-namespace content {
-class WebContents;
-}
-
-// Implements OmniboxView on an AutocompleteTextField.
-class OmniboxViewMac : public OmniboxView,
-                       public AutocompleteTextFieldObserver {
- public:
-  static SkColor BaseTextColorSkia(bool in_dark_mode);
-  static NSColor* BaseTextColor(bool in_dark_mode);
-  // Returns a color representing |security_level|, adjusted based on whether
-  // the browser is in Incognito mode.
-  static NSColor* GetSecureTextColor(
-      security_state::SecurityLevel security_level,
-      bool in_dark_mode);
-
-  OmniboxViewMac(OmniboxEditController* controller,
-                 Profile* profile,
-                 CommandUpdater* command_updater,
-                 AutocompleteTextField* field);
-  ~OmniboxViewMac() override;
-
-  // For use when switching tabs, this saves the current state onto the tab so
-  // that it can be restored during a later call to Update().
-  void SaveStateToTab(content::WebContents* tab);
-
-  // Called when the window's active tab changes.
-  void OnTabChanged(const content::WebContents* web_contents);
-
-  // Called to clear the saved state for |web_contents|.
-  void ResetTabState(content::WebContents* web_contents);
-
-  // OmniboxView:
-  void Update() override;
-  void OpenMatch(const AutocompleteMatch& match,
-                 WindowOpenDisposition disposition,
-                 const GURL& alternate_nav_url,
-                 const base::string16& pasted_text,
-                 size_t selected_line,
-                 base::TimeTicks match_selection_timestamp) override;
-  base::string16 GetText() const override;
-  void SetWindowTextAndCaretPos(const base::string16& text,
-                                size_t caret_pos,
-                                bool update_popup,
-                                bool notify_text_changed) override;
-  void SetCaretPos(size_t caret_pos) override;
-  void EnterKeywordModeForDefaultSearchProvider() override;
-  bool IsSelectAll() const override;
-  void GetSelectionBounds(base::string16::size_type* start,
-                          base::string16::size_type* end) const override;
-  void SelectAll(bool reversed) override;
-  void RevertAll() override;
-  void UpdatePopup() override;
-  void CloseOmniboxPopup() override;
-  void SetFocus() override;
-  void ApplyCaretVisibility() override;
-  void OnTemporaryTextMaybeChanged(const base::string16& display_text,
-                                   const AutocompleteMatch& match,
-                                   bool save_original_selection,
-                                   bool notify_text_changed) override;
-  bool OnInlineAutocompleteTextMaybeChanged(const base::string16& display_text,
-                                            size_t user_text_length) override;
-  void OnInlineAutocompleteTextCleared() override;
-  void OnRevertTemporaryText() override;
-  void OnBeforePossibleChange() override;
-  bool OnAfterPossibleChange(bool allow_keyword_ui_change) override;
-  gfx::NativeView GetNativeView() const override;
-  gfx::NativeView GetRelativeWindowForPopup() const override;
-  int GetTextWidth() const override;
-  int GetWidth() const override;
-  bool IsImeComposing() const override;
-
-  // Implement the AutocompleteTextFieldObserver interface.
-  NSRange SelectionRangeForProposedRange(NSRange proposed_range) override;
-  void OnControlKeyChanged(bool pressed) override;
-  bool CanCopy() override;
-  base::scoped_nsobject<NSPasteboardItem> CreatePasteboardItem() override;
-  void CopyToPasteboard(NSPasteboard* pboard) override;
-  void OnPaste() override;
-  bool CanPasteAndGo() override;
-  int GetPasteActionStringId() override;
-  void OnPasteAndGo() override;
-  void OnFrameChanged() override;
-  void ClosePopup() override;
-  void OnDidBeginEditing() override;
-  void OnBeforeChange() override;
-  void OnDidChange() override;
-  void OnDidEndEditing() override;
-  void OnInsertText() override;
-  void OnBeforeDrawRect() override;
-  void OnDidDrawRect() override;
-  bool OnDoCommandBySelector(SEL cmd) override;
-  void OnSetFocus(bool control_down) override;
-  void OnKillFocus() override;
-  void OnMouseDown(NSInteger button_number) override;
-
-  // Helper for LocationBarViewMac.  Optionally selects all in |field_|.
-  void FocusLocation(bool select_all);
-
-  // Helper to get the font to use in the field, exposed for the
-  // popup.
-  static NSFont* GetNormalFieldFont();
-  static NSFont* GetBoldFieldFont();
-  static NSFont* GetLargeFont();
-  static NSFont* GetSmallFont();
-
-  // If |resource_id| has a PDF image which can be used, return it.
-  // Otherwise return the PNG image from the resource bundle.
-  static NSImage* ImageForResource(int resource_id);
-
-  // Color used to draw suggest text.
-  static NSColor* SuggestTextColor();
-
-  AutocompleteTextField* field() const { return field_; }
-
- private:
-  FRIEND_TEST_ALL_PREFIXES(OmniboxViewMacTest, WritingDirectionLTR);
-  FRIEND_TEST_ALL_PREFIXES(OmniboxViewMacTest, WritingDirectionRTL);
-  // Called when the user hits backspace in |field_|.  Checks whether
-  // keyword search is being terminated.  Returns true if the
-  // backspace should be intercepted (not forwarded on to the standard
-  // machinery).
-  bool OnBackspacePressed();
-
-  // Returns the field's currently selected range.  Only valid if the
-  // field has focus.
-  NSRange GetSelectedRange() const;
-
-  // Returns the field's currently marked range. Only valid if the field has
-  // focus.
-  NSRange GetMarkedRange() const;
-
-  // Returns true if |field_| is first-responder in the window.  Used
-  // in various DCHECKS to make sure code is running in appropriate
-  // situations.
-  bool IsFirstResponder() const;
-
-  // If |model_| believes it has focus, grab focus if needed and set
-  // the selection to |range|.  Otherwise does nothing.
-  void SetSelectedRange(const NSRange range);
-
-  // Update the field with |display_text| and highlight the host and scheme (if
-  // it's an URL or URL-fragment).  Resets any suggest text that may be present.
-  void SetText(const base::string16& display_text);
-
-  // Internal implementation of SetText.  Does not reset the suggest text before
-  // setting the display text.  Most callers should use |SetText()| instead.
-  void SetTextInternal(const base::string16& display_text);
-
-  // Update the field with |display_text| and set the selection.
-  void SetTextAndSelectedRange(const base::string16& display_text,
-                               const NSRange range);
-
-  // Pass the current content of |field_| to SetText(), maintaining
-  // any selection.  Named to be consistent with GTK and Windows,
-  // though here we cannot really do the in-place operation they do.
-  void EmphasizeURLComponents() override;
-
-  // Apply our font and paragraph style to |attributedString|.
-  void ApplyTextStyle(NSMutableAttributedString* attributedString);
-
-  // Calculates text attributes according to |display_text| and applies them
-  // to the given |attributed_string| object.
-  void ApplyTextAttributes(const base::string16& display_text,
-                           NSMutableAttributedString* attributed_string);
-
-  // OmniboxView:
-  void SetEmphasis(bool emphasize, const gfx::Range& range) override;
-  void UpdateSchemeStyle(const gfx::Range& scheme_range) override;
-
-  // Return the number of UTF-16 units in the current buffer, excluding the
-  // suggested text.
-  int GetOmniboxTextLength() const override;
-  NSUInteger GetTextLength() const;
-
-  // Returns true if the caret is at the end of the content.
-  bool IsCaretAtEnd() const;
-
-  // Announce that an inline autocomplete is available for screenreaders.
-  void AnnounceAutocompleteForScreenReader(const base::string16& text);
-
-  Profile* profile_;
-
-  std::unique_ptr<OmniboxPopupView> popup_view_;
-
-  AutocompleteTextField* field_;  // owned by tab controller
-
-  // Selection at the point where the user started using the
-  // arrows to move around in the popup.
-  NSRange saved_temporary_selection_;
-
-  // Tracking state before and after a possible change for reporting
-  // to model_.
-  State state_before_change_;
-  NSRange marked_range_before_change_;
-
-  // Was delete pressed?
-  bool delete_was_pressed_;
-
-  // State used to coalesce changes to text and selection to avoid drawing
-  // transient state.
-  bool in_coalesced_update_block_;
-  bool do_coalesced_text_update_;
-  base::string16 coalesced_text_update_;
-  bool do_coalesced_range_update_;
-  NSRange coalesced_range_update_;
-
-  // The time of the first character insert operation that has not yet been
-  // painted. Used to measure omnibox responsiveness with a histogram.
-  base::TimeTicks insert_char_time_;
-
-  // The time when OnBeforeDrawRect() was called.
-  base::TimeTicks draw_rect_start_time_;
-
-  // Temporary pointer to the attributed display string, stored as color and
-  // other emphasis attributes are applied by the superclass.
-  NSMutableAttributedString* attributing_display_string_;  // weak
-
-  DISALLOW_COPY_AND_ASSIGN(OmniboxViewMac);
-};
-
-#endif  // CHROME_BROWSER_UI_COCOA_OMNIBOX_OMNIBOX_VIEW_MAC_H_
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
deleted file mode 100644
index df24ddc..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
+++ /dev/null
@@ -1,1084 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-
-#include <Carbon/Carbon.h>  // kVK_Return
-
-#include "base/auto_reset.h"
-#include "base/mac/foundation_util.h"
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
-#include "chrome/browser/browser_process.h"
-#include "chrome/browser/search/search.h"
-#include "chrome/browser/themes/theme_service.h"
-#import "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
-#include "chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.h"
-#include "chrome/browser/ui/omnibox/chrome_omnibox_client.h"
-#include "chrome/browser/ui/omnibox/clipboard_utils.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/omnibox/browser/autocomplete_input.h"
-#include "components/omnibox/browser/autocomplete_match.h"
-#include "components/omnibox/browser/omnibox_edit_controller.h"
-#include "components/omnibox/browser/omnibox_field_trial.h"
-#include "components/omnibox/browser/omnibox_popup_model.h"
-#include "components/toolbar/toolbar_model.h"
-#include "content/public/browser/web_contents.h"
-#include "extensions/common/constants.h"
-#import "skia/ext/skia_utils_mac.h"
-#import "third_party/mozilla/NSPasteboard+Utils.h"
-#include "ui/base/clipboard/clipboard.h"
-#include "ui/base/clipboard/clipboard_util_mac.h"
-#import "ui/base/cocoa/cocoa_base_utils.h"
-#import "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/material_design/material_design_controller.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/color_palette.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/geometry/rect.h"
-
-using content::WebContents;
-
-// Focus-handling between |field_| and model() is a bit subtle.
-// Other platforms detect change of focus, which is inconvenient
-// without subclassing NSTextField (even with a subclass, the use of a
-// field editor may complicate things).
-//
-// model() doesn't actually do anything when it gains focus, it just
-// initializes.  Visible activity happens only after the user edits.
-// NSTextField delegate receives messages around starting and ending
-// edits, so that suffices to catch focus changes.  Since all calls
-// into model() start from OmniboxViewMac, in the worst case
-// we can add code to sync up the sense of focus as needed.
-//
-// I've added DCHECK(IsFirstResponder()) in the places which I believe
-// should only be reachable when |field_| is being edited.  If these
-// fire, it probably means someone unexpected is calling into
-// model().
-//
-// Other platforms don't appear to have the sense of "key window" that
-// Mac does (I believe their fields lose focus when the window loses
-// focus).  Rather than modifying focus outside the control's edit
-// scope, when the window resigns key the autocomplete popup is
-// closed.  model() still believes it has focus, and the popup will
-// be regenerated on the user's next edit.  That seems to match how
-// things work on other platforms.
-
-namespace {
-const int kOmniboxLargeFontSizeDelta = 9;
-const int kOmniboxNormalFontSizeDelta = 1;
-const int kOmniboxSmallMaterialFontSizeDelta = -1;
-
-NSColor* HostTextColor(bool in_dark_mode) {
-  return in_dark_mode ? [NSColor whiteColor] : [NSColor blackColor];
-}
-NSColor* SecureSchemeColor(bool in_dark_mode) {
-  return in_dark_mode ? skia::SkColorToSRGBNSColor(SK_ColorWHITE)
-                      : skia::SkColorToSRGBNSColor(gfx::kGoogleGreen700);
-}
-NSColor* SecurityErrorSchemeColor(bool in_dark_mode) {
-  return in_dark_mode
-      ? skia::SkColorToSRGBNSColor(SkColorSetA(SK_ColorWHITE, 0x7F))
-      : skia::SkColorToSRGBNSColor(gfx::kGoogleRed700);
-}
-
-const char kOmniboxViewMacStateKey[] = "OmniboxViewMacState";
-
-// Store's the model and view state across tab switches.
-struct OmniboxViewMacState : public base::SupportsUserData::Data {
-  OmniboxViewMacState(const OmniboxEditModel::State model_state,
-                      const bool has_focus,
-                      const NSRange& selection)
-      : model_state(model_state),
-        has_focus(has_focus),
-        selection(selection) {
-  }
-  ~OmniboxViewMacState() override {}
-
-  const OmniboxEditModel::State model_state;
-  const bool has_focus;
-  const NSRange selection;
-};
-
-// Accessors for storing and getting the state from the tab.
-void StoreStateToTab(WebContents* tab,
-                     std::unique_ptr<OmniboxViewMacState> state) {
-  tab->SetUserData(kOmniboxViewMacStateKey, std::move(state));
-}
-
-const OmniboxViewMacState* GetStateFromTab(const WebContents* tab) {
-  return static_cast<OmniboxViewMacState*>(
-      tab->GetUserData(&kOmniboxViewMacStateKey));
-}
-
-}  // namespace
-
-// static
-NSImage* OmniboxViewMac::ImageForResource(int resource_id) {
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  return rb.GetNativeImageNamed(resource_id).ToNSImage();
-}
-
-// static
-NSColor* OmniboxViewMac::SuggestTextColor() {
-  return [NSColor colorWithCalibratedWhite:0.0 alpha:0.5];
-}
-
-//static
-SkColor OmniboxViewMac::BaseTextColorSkia(bool in_dark_mode) {
-  return in_dark_mode ? SkColorSetA(SK_ColorWHITE, 0x7F)
-                      : SkColorSetA(SK_ColorBLACK, 0x7F);
-}
-
-// static
-NSColor* OmniboxViewMac::BaseTextColor(bool in_dark_mode) {
-  return skia::SkColorToSRGBNSColor(BaseTextColorSkia(in_dark_mode));
-}
-
-// static
-NSColor* OmniboxViewMac::GetSecureTextColor(
-    security_state::SecurityLevel security_level,
-    bool in_dark_mode) {
-  if (security_level == security_state::EV_SECURE ||
-      security_level == security_state::SECURE) {
-    return SecureSchemeColor(in_dark_mode);
-  }
-
-  DCHECK_EQ(security_state::DANGEROUS, security_level);
-  return SecurityErrorSchemeColor(in_dark_mode);
-}
-
-OmniboxViewMac::OmniboxViewMac(OmniboxEditController* controller,
-                               Profile* profile,
-                               CommandUpdater* command_updater,
-                               AutocompleteTextField* field)
-    : OmniboxView(
-          controller,
-          base::WrapUnique(new ChromeOmniboxClient(controller, profile))),
-      profile_(profile),
-      popup_view_(new OmniboxPopupViewMac(this, model(), field)),
-      field_(field),
-      saved_temporary_selection_(NSMakeRange(0, 0)),
-      marked_range_before_change_(NSMakeRange(0, 0)),
-      delete_was_pressed_(false),
-      in_coalesced_update_block_(false),
-      do_coalesced_text_update_(false),
-      do_coalesced_range_update_(false),
-      attributing_display_string_(nil) {
-  [field_ setObserver:this];
-
-  // Needed so that editing doesn't lose the styling.
-  [field_ setAllowsEditingTextAttributes:YES];
-
-  // Get the appropriate line height for the font that we use.
-  base::scoped_nsobject<NSLayoutManager> layoutManager(
-      [[NSLayoutManager alloc] init]);
-  [layoutManager setUsesScreenFonts:YES];
-}
-
-OmniboxViewMac::~OmniboxViewMac() {
-  // Destroy popup view before this object in case it tries to call us
-  // back in the destructor.
-  popup_view_.reset();
-
-  // Disconnect from |field_|, it outlives this object.
-  [field_ setObserver:NULL];
-}
-
-void OmniboxViewMac::SaveStateToTab(WebContents* tab) {
-  DCHECK(tab);
-
-  const bool hasFocus = [field_ currentEditor] ? true : false;
-
-  NSRange range;
-  if (hasFocus) {
-    range = GetSelectedRange();
-  } else {
-    // If we are not focused, there is no selection.  Manufacture
-    // something reasonable in case it starts to matter in the future.
-    range = NSMakeRange(0, GetTextLength());
-  }
-
-  StoreStateToTab(tab, std::make_unique<OmniboxViewMacState>(
-                           model()->GetStateForTabSwitch(), hasFocus, range));
-}
-
-void OmniboxViewMac::OnTabChanged(const WebContents* web_contents) {
-  const OmniboxViewMacState* state = GetStateFromTab(web_contents);
-  model()->RestoreState(state ? &state->model_state : NULL);
-  // Restore focus and selection if they were present when the tab
-  // was switched away.
-  if (state && state->has_focus) {
-// TODO(shess): Unfortunately, there is no safe way to update
-// this because TabStripControllerCocoa -selectTabWithContents:* is
-// also messing with focus.  Both parties need to agree to
-// store existing state before anyone tries to setup the new
-// state.  Anyhow, it would look something like this.
-#if 0
-    [[field_ window] makeFirstResponder:field_];
-    [[field_ currentEditor] setSelectedRange:state->selection];
-#endif
-  }
-}
-
-void OmniboxViewMac::ResetTabState(WebContents* web_contents) {
-  StoreStateToTab(web_contents, nullptr);
-}
-
-void OmniboxViewMac::Update() {
-  if (model()->ResetDisplayTexts()) {
-    // Restore everything to the baseline look.
-    RevertAll();
-
-    // Only select all when we have focus. It's incorrect to have the
-    // Omnibox text selected while unfocused, and we'll re-select it
-    // when focus returns.
-    if (model()->has_focus())
-      SelectAll(true);
-  } else {
-    // TODO(shess): This corresponds to _win and _gtk, except those
-    // guard it with a test for whether the security level changed.
-    // But AFAICT, that can only change if the text changed, and that
-    // code compares the toolbar model security level with the local
-    // security level.  Dig in and figure out why this isn't a no-op
-    // that should go away.
-    EmphasizeURLComponents();
-  }
-}
-
-void OmniboxViewMac::OpenMatch(const AutocompleteMatch& match,
-                               WindowOpenDisposition disposition,
-                               const GURL& alternate_nav_url,
-                               const base::string16& pasted_text,
-                               size_t selected_line,
-                               base::TimeTicks match_selection_timestamp) {
-  // Coalesce text and selection updates from the following function. If we
-  // don't do this, the user may see intermediate states as brief flickers.
-  in_coalesced_update_block_ = true;
-  OmniboxView::OpenMatch(match, disposition, alternate_nav_url, pasted_text,
-                         selected_line, match_selection_timestamp);
-  in_coalesced_update_block_ = false;
-  if (do_coalesced_text_update_) {
-    SetText(coalesced_text_update_);
-    // Ensure location bar icon is updated to reflect text.
-    controller()->OnChanged();
-  }
-  do_coalesced_text_update_ = false;
-  if (do_coalesced_range_update_)
-    SetSelectedRange(coalesced_range_update_);
-  do_coalesced_range_update_ = false;
-}
-
-base::string16 OmniboxViewMac::GetText() const {
-  return base::SysNSStringToUTF16([field_ stringValue]);
-}
-
-NSRange OmniboxViewMac::GetSelectedRange() const {
-  return [[field_ currentEditor] selectedRange];
-}
-
-NSRange OmniboxViewMac::GetMarkedRange() const {
-  DCHECK([field_ currentEditor]);
-  return [(NSTextView*)[field_ currentEditor] markedRange];
-}
-
-void OmniboxViewMac::SetSelectedRange(const NSRange range) {
-  if (in_coalesced_update_block_) {
-    do_coalesced_range_update_ = true;
-    coalesced_range_update_ = range;
-    return;
-  }
-
-  // This can be called when we don't have focus.  For instance, when
-  // the user clicks the "Go" button.
-  if (model()->has_focus()) {
-    // TODO(shess): If model() thinks we have focus, this should not
-    // be necessary.  Try to convert to DCHECK(IsFirstResponder()).
-    if (![field_ currentEditor]) {
-      [[field_ window] makeFirstResponder:field_];
-    }
-
-    // TODO(shess): What if it didn't get first responder, and there is
-    // no field editor?  This will do nothing.  Well, at least it won't
-    // crash.  Think of something more productive to do, or prove that
-    // it cannot occur and DCHECK appropriately.
-    [[field_ currentEditor] setSelectedRange:range];
-  }
-}
-
-void OmniboxViewMac::SetWindowTextAndCaretPos(const base::string16& text,
-                                              size_t caret_pos,
-                                              bool update_popup,
-                                              bool notify_text_changed) {
-  DCHECK_LE(caret_pos, text.size());
-  SetTextAndSelectedRange(text, NSMakeRange(caret_pos, 0));
-
-  if (update_popup)
-    UpdatePopup();
-
-  if (notify_text_changed)
-    TextChanged();
-}
-
-void OmniboxViewMac::SetCaretPos(size_t caret_pos) {
-  size_t pos = std::min(caret_pos, GetTextLength());
-  SetSelectedRange(NSMakeRange(pos, 0));
-}
-
-void OmniboxViewMac::EnterKeywordModeForDefaultSearchProvider() {
-  // We need to do this first, else |SetSelectedRange()| won't work.
-  FocusLocation(true);
-
-  // Transition the user into keyword mode using their default search provider.
-  model()->EnterKeywordModeForDefaultSearchProvider(
-      KeywordModeEntryMethod::KEYBOARD_SHORTCUT);
-}
-
-bool OmniboxViewMac::IsSelectAll() const {
-  if (![field_ currentEditor])
-    return true;
-  const NSRange all_range = NSMakeRange(0, GetTextLength());
-  if (all_range.length == 0)
-    return false;
-  return NSEqualRanges(all_range, GetSelectedRange());
-}
-
-void OmniboxViewMac::GetSelectionBounds(base::string16::size_type* start,
-                                        base::string16::size_type* end) const {
-  if (![field_ currentEditor]) {
-    *start = *end = 0;
-    return;
-  }
-
-  const NSRange selected_range = GetSelectedRange();
-  *start = static_cast<size_t>(selected_range.location);
-  *end = static_cast<size_t>(NSMaxRange(selected_range));
-}
-
-void OmniboxViewMac::SelectAll(bool reversed) {
-  if (!model()->has_focus())
-    return;
-
-  NSRange full_range = NSMakeRange(0, GetTextLength());
-
-  // When coalescing updates, just set the range and not the direction. It's
-  // unlikely that the direction will matter after OpenMatch() applies updates.
-  if (in_coalesced_update_block_) {
-    SetSelectedRange(full_range);
-    return;
-  }
-
-  NSTextView* text_view =
-      base::mac::ObjCCastStrict<NSTextView>([field_ currentEditor]);
-  NSSelectionAffinity affinity =
-      reversed ? NSSelectionAffinityUpstream : NSSelectionAffinityDownstream;
-
-  [text_view setSelectedRange:full_range affinity:affinity stillSelecting:NO];
-}
-
-void OmniboxViewMac::RevertAll() {
-  OmniboxView::RevertAll();
-  [field_ clearUndoChain];
-}
-
-void OmniboxViewMac::UpdatePopup() {
-  // Comment copied from OmniboxViewWin::UpdatePopup():
-  // Don't inline autocomplete when:
-  //   * The user is deleting text
-  //   * The caret/selection isn't at the end of the text
-  //   * The user has just pasted in something that replaced all the text
-  //   * The user is trying to compose something in an IME
-  bool prevent_inline_autocomplete = IsImeComposing();
-  NSTextView* editor = (NSTextView*)[field_ currentEditor];
-  if (editor) {
-    if (NSMaxRange([editor selectedRange]) < [[editor textStorage] length])
-      prevent_inline_autocomplete = true;
-  }
-
-  model()->UpdateInput([editor selectedRange].length != 0,
-                       prevent_inline_autocomplete);
-}
-
-void OmniboxViewMac::CloseOmniboxPopup() {
-  // Call both base class methods.
-  ClosePopup();
-  OmniboxView::CloseOmniboxPopup();
-}
-
-void OmniboxViewMac::SetFocus() {
-  FocusLocation(false);
-  model()->SetCaretVisibility(true);
-}
-
-void OmniboxViewMac::ApplyCaretVisibility() {
-  [[field_ cell] setHideFocusState:!model()->is_caret_visible()
-                            ofView:field_];
-}
-
-void OmniboxViewMac::SetText(const base::string16& display_text) {
-  SetTextInternal(display_text);
-}
-
-void OmniboxViewMac::SetTextInternal(const base::string16& display_text) {
-  if (in_coalesced_update_block_) {
-    do_coalesced_text_update_ = true;
-    coalesced_text_update_ = display_text;
-    // Don't do any selection changes, since they apply to the previous text.
-    do_coalesced_range_update_ = false;
-    return;
-  }
-
-  NSString* ss = base::SysUTF16ToNSString(display_text);
-  NSMutableAttributedString* attributedString =
-      [[[NSMutableAttributedString alloc] initWithString:ss] autorelease];
-
-  ApplyTextAttributes(display_text, attributedString);
-  [field_ setAttributedStringValue:attributedString];
-
-  // TODO(shess): This may be an appropriate place to call:
-  //   model()->OnChanged();
-  // In the current implementation, this tells LocationBarViewMac to
-  // mess around with model() and update |field_|.  Unfortunately,
-  // when I look at our peer implementations, it's not entirely clear
-  // to me if this is safe.  SetTextInternal() is sort of an utility method,
-  // and different callers sometimes have different needs.  Research
-  // this issue so that it can be added safely.
-
-  // TODO(shess): Also, consider whether this code couldn't just
-  // manage things directly.  Windows uses a series of overlaid view
-  // objects to accomplish the hinting stuff that OnChanged() does, so
-  // it makes sense to have it in the controller that lays those
-  // things out.  Mac instead pushes the support into a custom
-  // text-field implementation.
-}
-
-void OmniboxViewMac::SetTextAndSelectedRange(const base::string16& display_text,
-                                             const NSRange range) {
-  SetText(display_text);
-  SetSelectedRange(range);
-}
-
-void OmniboxViewMac::EmphasizeURLComponents() {
-  NSTextView* editor = (NSTextView*)[field_ currentEditor];
-  // If the autocomplete text field is in editing mode, then we can just change
-  // its attributes through its editor. Otherwise, we simply reset its content.
-  if (editor) {
-    NSTextStorage* storage = [editor textStorage];
-    [storage beginEditing];
-
-    // Clear the existing attributes from the text storage, then
-    // overlay the appropriate Omnibox attributes.
-    [storage setAttributes:[NSDictionary dictionary]
-                     range:NSMakeRange(0, [storage length])];
-    ApplyTextAttributes(GetText(), storage);
-
-    [storage endEditing];
-
-    // This function can be called during the editor's -resignFirstResponder. If
-    // that happens, |storage| and |field_| will not be synced automatically any
-    // more. Calling -stringValue ensures that |field_| reflects the changes to
-    // |storage|.
-    [field_ stringValue];
-  } else if (!in_coalesced_update_block_) {
-    // Skip this if we're in a coalesced update block. Otherwise, the user text
-    // entered can get set in a new tab because we haven't yet set the URL text.
-    SetText(GetText());
-  }
-}
-
-void OmniboxViewMac::ApplyTextStyle(
-    NSMutableAttributedString* attributedString) {
-  [attributedString addAttribute:NSFontAttributeName
-                           value:GetNormalFieldFont()
-                           range:NSMakeRange(0, [attributedString length])];
-
-  // Make a paragraph style locking in the standard line height as the maximum,
-  // otherwise the baseline may shift "downwards".
-  base::scoped_nsobject<NSMutableParagraphStyle> paragraph_style(
-      [[NSMutableParagraphStyle alloc] init]);
-  CGFloat line_height = [[field_ cell] lineHeight];
-  [paragraph_style setMaximumLineHeight:line_height];
-  [paragraph_style setMinimumLineHeight:line_height];
-  [paragraph_style setLineBreakMode:NSLineBreakByTruncatingTail];
-  // Set an explicit alignment so it isn't implied from writing direction.
-  [paragraph_style setAlignment:cocoa_l10n_util::ShouldDoExperimentalRTLLayout()
-                                    ? NSRightTextAlignment
-                                    : NSLeftTextAlignment];
-  if (@available(macOS 10.11, *))
-    [paragraph_style setAllowsDefaultTighteningForTruncation:NO];
-  // If this is a URL, set the top-level paragraph direction to LTR (avoids RTL
-  // characters from making the URL render from right to left, as per RFC 3987
-  // Section 4.1).
-  if (model()->CurrentTextIsURL())
-    [paragraph_style setBaseWritingDirection:NSWritingDirectionLeftToRight];
-  [attributedString addAttribute:NSParagraphStyleAttributeName
-                           value:paragraph_style
-                           range:NSMakeRange(0, [attributedString length])];
-}
-
-void OmniboxViewMac::SetEmphasis(bool emphasize, const gfx::Range& range) {
-  bool in_dark_mode = [[field_ window] inIncognitoModeWithSystemTheme];
-
-  NSRange ns_range = range.IsValid()
-                         ? range.ToNSRange()
-                         : NSMakeRange(0, [attributing_display_string_ length]);
-
-  [attributing_display_string_
-      addAttribute:NSForegroundColorAttributeName
-             value:(emphasize) ? HostTextColor(in_dark_mode)
-                               : BaseTextColor(in_dark_mode)
-             range:ns_range];
-}
-
-void OmniboxViewMac::UpdateSchemeStyle(const gfx::Range& range) {
-  if (!range.IsValid())
-    return;
-
-  const security_state::SecurityLevel security_level =
-      controller()->GetToolbarModel()->GetSecurityLevel(false);
-
-  if ((security_level == security_state::NONE) ||
-      (security_level == security_state::HTTP_SHOW_WARNING))
-    return;
-
-  if (security_level == security_state::DANGEROUS) {
-    // Add a strikethrough through the scheme.
-    [attributing_display_string_
-        addAttribute:NSStrikethroughStyleAttributeName
-               value:[NSNumber numberWithInt:NSUnderlineStyleSingle]
-               range:range.ToNSRange()];
-  }
-
-  bool in_dark_mode = [[field_ window] inIncognitoModeWithSystemTheme];
-
-  [attributing_display_string_
-      addAttribute:NSForegroundColorAttributeName
-             value:GetSecureTextColor(security_level, in_dark_mode)
-             range:range.ToNSRange()];
-}
-
-void OmniboxViewMac::ApplyTextAttributes(
-    const base::string16& display_text,
-    NSMutableAttributedString* attributed_string) {
-  NSUInteger as_length = [attributed_string length];
-  if (as_length == 0) {
-    return;
-  }
-
-  ApplyTextStyle(attributed_string);
-
-  // A kinda hacky way to add breaking at periods. This is what Safari does.
-  // This works for IDNs too, despite the "en_US".
-  [attributed_string addAttribute:@"NSLanguage"
-                            value:@"en_US_POSIX"
-                            range:NSMakeRange(0, as_length)];
-
-  // Cache a pointer to the attributed string to allow the superclass'
-  // virtual method invocations to add attributes.
-  DCHECK(attributing_display_string_ == nil);
-  base::AutoReset<NSMutableAttributedString*> resetter(
-      &attributing_display_string_, attributed_string);
-  UpdateTextStyle(display_text, model()->CurrentTextIsURL(),
-                  ChromeAutocompleteSchemeClassifier(profile_));
-}
-
-void OmniboxViewMac::OnTemporaryTextMaybeChanged(
-    const base::string16& display_text,
-    const AutocompleteMatch& match,
-    bool save_original_selection,
-    bool notify_text_changed) {
-  if (save_original_selection)
-    saved_temporary_selection_ = GetSelectedRange();
-
-  SetWindowTextAndCaretPos(display_text, display_text.size(), false, false);
-  if (notify_text_changed)
-    model()->OnChanged();
-  [field_ clearUndoChain];
-
-  // Get friendly accessibility label.
-  AnnounceAutocompleteForScreenReader(
-      AutocompleteMatchType::ToAccessibilityLabel(
-          match, display_text, model()->popup_model()->selected_line(),
-          model()->result().size(), false));
-}
-
-bool OmniboxViewMac::OnInlineAutocompleteTextMaybeChanged(
-    const base::string16& display_text,
-    size_t user_text_length) {
-  // TODO(shess): Make sure that this actually works.  The round trip
-  // to native form and back may mean that it's the same but not the
-  // same.
-  if (display_text == GetText())
-    return false;
-
-  DCHECK_LE(user_text_length, display_text.size());
-  const NSRange range =
-      NSMakeRange(user_text_length, display_text.size() - user_text_length);
-  SetTextAndSelectedRange(display_text, range);
-  model()->OnChanged();
-  [field_ clearUndoChain];
-
-  AnnounceAutocompleteForScreenReader(display_text);
-
-  return true;
-}
-
-void OmniboxViewMac::OnInlineAutocompleteTextCleared() {
-}
-
-void OmniboxViewMac::OnRevertTemporaryText() {
-  SetSelectedRange(saved_temporary_selection_);
-  // We got here because the user hit the Escape key. We explicitly don't call
-  // TextChanged(), since OmniboxPopupModel::ResetToDefaultMatch() has already
-  // been called by now, and it would've called TextChanged() if it was
-  // warranted.
-}
-
-bool OmniboxViewMac::IsFirstResponder() const {
-  return [field_ currentEditor] != nil ? true : false;
-}
-
-void OmniboxViewMac::OnBeforePossibleChange() {
-  // We should only arrive here when the field is focused.
-  DCHECK(IsFirstResponder());
-
-  GetState(&state_before_change_);
-  marked_range_before_change_ = GetMarkedRange();
-}
-
-bool OmniboxViewMac::OnAfterPossibleChange(bool allow_keyword_ui_change) {
-  // We should only arrive here when the field is focused.
-  DCHECK(IsFirstResponder());
-
-  State new_state;
-  GetState(&new_state);
-  OmniboxView::StateChanges state_changes =
-      GetStateChanges(state_before_change_, new_state);
-
-  const bool something_changed = model()->OnAfterPossibleChange(
-      state_changes, allow_keyword_ui_change && !IsImeComposing());
-
-  // Restyle in case the user changed something.
-  // TODO(shess): I believe there are multiple-redraw cases, here.
-  // Linux watches for something_changed && text_differs, but that
-  // fails for us in case you copy the URL and paste the identical URL
-  // back (we'll lose the styling).
-  TextChanged();
-
-  delete_was_pressed_ = false;
-
-  return something_changed;
-}
-
-gfx::NativeView OmniboxViewMac::GetNativeView() const {
-  return field_;
-}
-
-gfx::NativeView OmniboxViewMac::GetRelativeWindowForPopup() const {
-  // Not used on mac.
-  NOTREACHED();
-  return NULL;
-}
-
-int OmniboxViewMac::GetTextWidth() const {
-  // Not used on mac.
-  NOTREACHED();
-  return 0;
-}
-
-int OmniboxViewMac::GetWidth() const {
-  return ceil([field_ bounds].size.width);
-}
-
-bool OmniboxViewMac::IsImeComposing() const {
-  return [(NSTextView*)[field_ currentEditor] hasMarkedText];
-}
-
-void OmniboxViewMac::OnDidBeginEditing() {
-  // We should only arrive here when the field is focused.
-  DCHECK([field_ currentEditor]);
-}
-
-void OmniboxViewMac::OnBeforeChange() {
-  // Capture the current state.
-  OnBeforePossibleChange();
-}
-
-void OmniboxViewMac::OnDidChange() {
-  // Figure out what changed and notify the model.
-  OnAfterPossibleChange(true);
-}
-
-void OmniboxViewMac::OnDidEndEditing() {
-  ClosePopup();
-}
-
-void OmniboxViewMac::OnInsertText() {
-  // If |insert_char_time_| is not null, there's a pending insert char operation
-  // that hasn't been painted yet. Keep the earlier time.
-  if (insert_char_time_.is_null())
-    insert_char_time_ = base::TimeTicks::Now();
-}
-
-void OmniboxViewMac::OnBeforeDrawRect() {
-  if (!insert_char_time_.is_null()) {
-    UMA_HISTOGRAM_TIMES("Omnibox.CharTypedToRepaintLatency.ToPaint",
-                        base::TimeTicks::Now() - insert_char_time_);
-  }
-  draw_rect_start_time_ = base::TimeTicks::Now();
-}
-
-void OmniboxViewMac::OnDidDrawRect() {
-  base::TimeTicks now = base::TimeTicks::Now();
-  UMA_HISTOGRAM_TIMES("Omnibox.PaintTime", now - draw_rect_start_time_);
-  if (!insert_char_time_.is_null()) {
-    UMA_HISTOGRAM_TIMES("Omnibox.CharTypedToRepaintLatency",
-                        now - insert_char_time_);
-    insert_char_time_ = base::TimeTicks();
-  }
-}
-
-bool OmniboxViewMac::OnDoCommandBySelector(SEL cmd) {
-  if (cmd == @selector(deleteForward:))
-    delete_was_pressed_ = true;
-
-  if (cmd == @selector(moveDown:)) {
-    model()->OnUpOrDownKeyPressed(1);
-    return true;
-  }
-
-  if (cmd == @selector(moveUp:)) {
-    model()->OnUpOrDownKeyPressed(-1);
-    return true;
-  }
-
-  if (model()->popup_model()->IsOpen()) {
-    if (cmd == @selector(insertBacktab:)) {
-      if (model()->popup_model()->selected_line_state() ==
-            OmniboxPopupModel::KEYWORD) {
-        model()->ClearKeyword();
-        return true;
-      } else {
-        model()->OnUpOrDownKeyPressed(-1);
-        return true;
-      }
-    }
-
-    if ((cmd == @selector(insertTab:) ||
-        cmd == @selector(insertTabIgnoringFieldEditor:)) &&
-        !model()->is_keyword_hint()) {
-      model()->OnUpOrDownKeyPressed(1);
-      return true;
-    }
-  }
-
-  if (cmd == @selector(scrollPageDown:)) {
-    model()->OnUpOrDownKeyPressed(model()->result().size());
-    return true;
-  }
-
-  if (cmd == @selector(scrollPageUp:)) {
-    model()->OnUpOrDownKeyPressed(-model()->result().size());
-    return true;
-  }
-
-  if (cmd == @selector(cancelOperation:)) {
-    return model()->OnEscapeKeyPressed();
-  }
-
-  if ((cmd == @selector(insertTab:) ||
-      cmd == @selector(insertTabIgnoringFieldEditor:)) &&
-      model()->is_keyword_hint()) {
-    return model()->AcceptKeyword(KeywordModeEntryMethod::TAB);
-  }
-
-  // |-noop:| is sent when the user presses Cmd+Return. Override the no-op
-  // behavior with the proper WindowOpenDisposition.
-  NSEvent* event = [NSApp currentEvent];
-  if (cmd == @selector(insertNewline:) ||
-     (cmd == @selector(noop:) &&
-      ([event type] == NSKeyDown || [event type] == NSKeyUp) &&
-      [event keyCode] == kVK_Return)) {
-    // If the user hasn't entered any text in keyword search mode, we need to
-    // return early in order to avoid cancelling the search.
-    if (GetTextLength() == 0)
-      return true;
-
-    WindowOpenDisposition disposition =
-        ui::WindowOpenDispositionFromNSEvent(event);
-    model()->AcceptInput(disposition, false);
-    // Opening a URL in a background tab should also revert the omnibox contents
-    // to their original state.  We cannot do a blanket revert in OpenURL()
-    // because middle-clicks also open in a new background tab, but those should
-    // not revert the omnibox text.
-    RevertAll();
-    return true;
-  }
-
-  // Option-Return
-  if (cmd == @selector(insertNewlineIgnoringFieldEditor:)) {
-    model()->AcceptInput(WindowOpenDisposition::NEW_FOREGROUND_TAB, false);
-    return true;
-  }
-
-  // When the user does Control-Enter, the existing content has "www."
-  // prepended and ".com" appended.  model() should already have
-  // received notification when the Control key was depressed, but it
-  // is safe to tell it twice.
-  if (cmd == @selector(insertLineBreak:)) {
-    OnControlKeyChanged(true);
-    WindowOpenDisposition disposition =
-        ui::WindowOpenDispositionFromNSEvent([NSApp currentEvent]);
-    model()->AcceptInput(disposition, false);
-    return true;
-  }
-
-  if (cmd == @selector(deleteBackward:)) {
-    if (OnBackspacePressed()) {
-      return true;
-    }
-  }
-
-  if (cmd == @selector(deleteForward:)) {
-    const NSUInteger modifiers = [[NSApp currentEvent] modifierFlags];
-    if ((modifiers & NSShiftKeyMask) != 0) {
-      if (model()->popup_model()->IsOpen()) {
-        model()->popup_model()->TryDeletingCurrentItem();
-        return true;
-      }
-    }
-  }
-
-  return false;
-}
-
-void OmniboxViewMac::OnSetFocus(bool control_down) {
-  model()->OnSetFocus(control_down);
-  // Update the keyword and search hint states.
-  controller()->OnChanged();
-}
-
-void OmniboxViewMac::OnKillFocus() {
-  // Tell the model to reset itself.
-  model()->OnWillKillFocus();
-  model()->OnKillFocus();
-}
-
-void OmniboxViewMac::OnMouseDown(NSInteger button_number) {
-  // Restore caret visibility whenever the user clicks in the the omnibox. This
-  // is not always covered by OnSetFocus() because when clicking while the
-  // omnibox has invisible focus does not trigger a new OnSetFocus() call.
-  if (button_number == 0 || button_number == 1)
-    model()->SetCaretVisibility(true);
-}
-
-bool OmniboxViewMac::CanCopy() {
-  const NSRange selection = GetSelectedRange();
-  return selection.length > 0;
-}
-
-base::scoped_nsobject<NSPasteboardItem> OmniboxViewMac::CreatePasteboardItem() {
-  DCHECK(CanCopy());
-
-  const NSRange selection = GetSelectedRange();
-  base::string16 text = base::SysNSStringToUTF16(
-      [[field_ stringValue] substringWithRange:selection]);
-
-  // Copy the URL.
-  GURL url;
-  bool write_url = false;
-  model()->AdjustTextForCopy(selection.location, &text, &url, &write_url);
-
-  if (IsSelectAll())
-    UMA_HISTOGRAM_COUNTS_1M(OmniboxEditModel::kCutOrCopyAllTextHistogram, 1);
-
-  NSString* nstext = base::SysUTF16ToNSString(text);
-  if (write_url) {
-    return ui::ClipboardUtil::PasteboardItemFromUrl(
-        base::SysUTF8ToNSString(url.spec()), nstext);
-  } else {
-    return ui::ClipboardUtil::PasteboardItemFromString(nstext);
-  }
-}
-
-void OmniboxViewMac::CopyToPasteboard(NSPasteboard* pboard) {
-  [pboard clearContents];
-  base::scoped_nsobject<NSPasteboardItem> item(CreatePasteboardItem());
-  [pboard writeObjects:@[ item.get() ]];
-}
-
-void OmniboxViewMac::OnPaste() {
-  // This code currently expects |field_| to be focused.
-  DCHECK([field_ currentEditor]);
-
-  base::string16 text = GetClipboardText();
-  if (text.empty()) {
-    return;
-  }
-  NSString* s = base::SysUTF16ToNSString(text);
-
-  // -shouldChangeTextInRange:* and -didChangeText are documented in
-  // NSTextView as things you need to do if you write additional
-  // user-initiated editing functions.  They cause the appropriate
-  // delegate methods to be called.
-  // TODO(shess): It would be nice to separate the Cocoa-specific code
-  // from the Chrome-specific code.
-  NSTextView* editor = static_cast<NSTextView*>([field_ currentEditor]);
-  const NSRange selectedRange = GetSelectedRange();
-  if ([editor shouldChangeTextInRange:selectedRange replacementString:s]) {
-    // Record this paste, so we can do different behavior.
-    model()->OnPaste();
-
-    // Force a Paste operation to trigger the text_changed code in
-    // OnAfterPossibleChange(), even if identical contents are pasted
-    // into the text box.
-    state_before_change_.text.clear();
-
-    [editor replaceCharactersInRange:selectedRange withString:s];
-    [editor didChangeText];
-  }
-}
-
-bool OmniboxViewMac::CanPasteAndGo() {
-  return model()->CanPasteAndGo(GetClipboardText());
-}
-
-int OmniboxViewMac::GetPasteActionStringId() {
-  base::string16 text(GetClipboardText());
-  DCHECK(model()->CanPasteAndGo(text));
-  return model()->ClassifiesAsSearch(text) ? IDS_PASTE_AND_SEARCH
-                                           : IDS_PASTE_AND_GO;
-}
-
-void OmniboxViewMac::OnPasteAndGo() {
-  base::string16 text(GetClipboardText());
-  if (model()->CanPasteAndGo(text))
-    model()->PasteAndGo(text);
-}
-
-void OmniboxViewMac::OnFrameChanged() {
-  // TODO(shess): UpdatePopupAppearance() is called frequently, so it
-  // should be really cheap, but in this case we could probably make
-  // things even cheaper by refactoring between the popup-placement
-  // code and the matrix-population code.
-  popup_view_->UpdatePopupAppearance();
-
-  // Give controller a chance to rearrange decorations.
-  model()->OnChanged();
-}
-
-void OmniboxViewMac::ClosePopup() {
-  OmniboxView::CloseOmniboxPopup();
-}
-
-bool OmniboxViewMac::OnBackspacePressed() {
-  // Don't intercept if not in keyword search mode.
-  if (model()->is_keyword_hint() || model()->keyword().empty()) {
-    return false;
-  }
-
-  // Don't intercept if there is a selection, or the cursor isn't at
-  // the leftmost position.
-  const NSRange selection = GetSelectedRange();
-  if (selection.length > 0 || selection.location > 0) {
-    return false;
-  }
-
-  // We're showing a keyword and the user pressed backspace at the
-  // beginning of the text.  Delete the selected keyword.
-  model()->ClearKeyword();
-  return true;
-}
-
-NSRange OmniboxViewMac::SelectionRangeForProposedRange(NSRange proposed_range) {
-  return proposed_range;
-}
-
-void OmniboxViewMac::OnControlKeyChanged(bool pressed) {
-  model()->OnControlKeyChanged(pressed);
-}
-
-void OmniboxViewMac::FocusLocation(bool select_all) {
-  if ([field_ isEditable]) {
-    // If the text field has a field editor, it's the first responder, meaning
-    // that it's already focused. makeFirstResponder: will select all, so only
-    // call it if this behavior is desired.
-    if (select_all || ![field_ currentEditor])
-      [[field_ window] makeFirstResponder:field_];
-    DCHECK_EQ([field_ currentEditor], [[field_ window] firstResponder]);
-  }
-}
-
-// static
-NSFont* OmniboxViewMac::GetNormalFieldFont() {
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  return rb
-      .GetFontWithDelta(kOmniboxNormalFontSizeDelta, gfx::Font::NORMAL,
-                        gfx::Font::Weight::NORMAL)
-      .GetNativeFont();
-}
-
-NSFont* OmniboxViewMac::GetBoldFieldFont() {
-  // Request a bold font, then make it larger. ResourceBundle will do the
-  // opposite which makes a large system normal font a non-system bold font.
-  // That gives a different baseline to making the non-system bold font larger.
-  // And while the omnibox locks the baseline in ApplyTextStyle(),
-  // OmniboxPopupCellData does not.
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  return rb
-      .GetFontWithDelta(0, gfx::Font::NORMAL, gfx::Font::Weight::BOLD)
-      .Derive(kOmniboxNormalFontSizeDelta, gfx::Font::NORMAL,
-              gfx::Font::Weight::BOLD)
-      .GetNativeFont();
-}
-
-NSFont* OmniboxViewMac::GetLargeFont() {
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  return rb
-      .GetFontWithDelta(kOmniboxLargeFontSizeDelta, gfx::Font::NORMAL,
-                        gfx::Font::Weight::NORMAL)
-      .GetNativeFont();
-}
-
-NSFont* OmniboxViewMac::GetSmallFont() {
-  return ui::ResourceBundle::GetSharedInstance()
-      .GetFontWithDelta(kOmniboxSmallMaterialFontSizeDelta, gfx::Font::NORMAL,
-                        gfx::Font::Weight::NORMAL)
-      .GetNativeFont();
-}
-
-int OmniboxViewMac::GetOmniboxTextLength() const {
-  return static_cast<int>(GetTextLength());
-}
-
-NSUInteger OmniboxViewMac::GetTextLength() const {
-  return [field_ currentEditor] ?  [[[field_ currentEditor] string] length] :
-                                   [[field_ stringValue] length];
-}
-
-bool OmniboxViewMac::IsCaretAtEnd() const {
-  const NSRange selection = GetSelectedRange();
-  return NSMaxRange(selection) == GetTextLength();
-}
-
-void OmniboxViewMac::AnnounceAutocompleteForScreenReader(
-    const base::string16& display_text) {
-  NSDictionary* notification_info = @{
-    NSAccessibilityAnnouncementKey : base::SysUTF16ToNSString(display_text),
-    NSAccessibilityPriorityKey : @(NSAccessibilityPriorityHigh)
-  };
-  // We direct the screen reader to announce the friendly text.
-  NSAccessibilityPostNotificationWithUserInfo(
-      [field_ window],
-      NSAccessibilityAnnouncementRequestedNotification,
-      notification_info);
-}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_browsertest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_browsertest.mm
deleted file mode 100644
index 9fd195a..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_browsertest.mm
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h"
-#include "chrome/browser/ui/location_bar/location_bar.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/views/scoped_macviews_browser_mode.h"
-#include "components/omnibox/browser/omnibox_edit_model.h"
-#include "ui/base/clipboard/clipboard_util_mac.h"
-
-class OmniboxViewMacBrowserTest : public InProcessBrowserTest {
- public:
-  OmniboxViewMac* GetOmnibox() {
-    return static_cast<OmniboxViewMac*>(
-        browser()->window()->GetLocationBar()->GetOmniboxView());
-  }
-
- private:
-  test::ScopedMacViewsBrowserMode cocoa_browser_mode_{false};
-};
-
-// Verify that the OmniboxViewMac::SetFocus API works.
-IN_PROC_BROWSER_TEST_F(OmniboxViewMacBrowserTest, SetFocus) {
-  EXPECT_FALSE([[GetOmnibox()->field() window] firstResponder] ==
-                GetOmnibox()->field());
-  GetOmnibox()->SetFocus();
-  // Unfortunately there's no way to test that the field has keyboard focus.
-}
-
-// Verify that the OmniboxViewMac::ApplyCaretVisibility API works.
-IN_PROC_BROWSER_TEST_F(OmniboxViewMacBrowserTest, ApplyCaretVisibility) {
-  EXPECT_FALSE([[GetOmnibox()->field() cell] hideFocusState]);
-
-  // |SetCaretVisibility(false)| should hide focus state.
-  GetOmnibox()->model()->SetCaretVisibility(false);
-  GetOmnibox()->ApplyCaretVisibility();
-  EXPECT_TRUE([[GetOmnibox()->field() cell] hideFocusState]);
-
-  // |SetCaretVisibility(true)| should show focus state.
-  GetOmnibox()->model()->SetCaretVisibility(true);
-  GetOmnibox()->ApplyCaretVisibility();
-  EXPECT_FALSE([[GetOmnibox()->field() cell] hideFocusState]);
-
-  // Focusing on the omnibox should show focus state.
-  GetOmnibox()->model()->SetCaretVisibility(false);
-  GetOmnibox()->ApplyCaretVisibility();
-  EXPECT_TRUE([[GetOmnibox()->field() cell] hideFocusState]);
-  GetOmnibox()->SetFocus();
-  EXPECT_FALSE([[GetOmnibox()->field() cell] hideFocusState]);
-}
-
-
-// Verify that mouse down sets caret visibility to true.
-IN_PROC_BROWSER_TEST_F(OmniboxViewMacBrowserTest, MouseDownCaretVisibility) {
-  GetOmnibox()->model()->SetCaretVisibility(false);
-  EXPECT_FALSE(GetOmnibox()->model()->is_caret_visible());
-  GetOmnibox()->OnMouseDown(0);
-  EXPECT_TRUE(GetOmnibox()->model()->is_caret_visible());
-}
-
-// Verify that copying text from the omnibox into the pasteboard works.
-IN_PROC_BROWSER_TEST_F(OmniboxViewMacBrowserTest, CopyToPasteboard) {
-  std::string text = "orange yam";
-  NSString* pboard_type = @"com.google.chrome.asdf";
-
-  scoped_refptr<ui::UniquePasteboard> pasteboard = new ui::UniquePasteboard;
-  [[GetOmnibox()->field() currentEditor]
-      setString:base::SysUTF8ToNSString(text)];
-  [[GetOmnibox()->field() currentEditor]
-      setSelectedRange:NSMakeRange(0, text.size())];
-
-  GetOmnibox()->model()->SetUserText(base::UTF8ToUTF16(text));
-  GetOmnibox()->CopyToPasteboard(pasteboard->get());
-
-  NSString* pasteboard_string =
-      [pasteboard->get() stringForType:NSPasteboardTypeString];
-  EXPECT_EQ(text, pasteboard_string.UTF8String);
-
-  // Clear the pasteboard and set some new contents, using a custom Pboard type.
-  [pasteboard->get() clearContents];
-  [pasteboard->get()
-      setString:@"bad result"
-        forType:ui::ClipboardUtil::UTIForPasteboardType(pboard_type)];
-  GetOmnibox()->CopyToPasteboard(pasteboard->get());
-
-  // Check that the custom Pboard type is no longer present.
-  EXPECT_FALSE([pasteboard->get()
-      stringForType:ui::ClipboardUtil::UTIForPasteboardType(pboard_type)]);
-
-  // Check that the contents of the omnibox were copied to the clipboard.
-  pasteboard_string = [pasteboard->get() stringForType:NSPasteboardTypeString];
-  EXPECT_EQ(text, pasteboard_string.UTF8String);
-}
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
deleted file mode 100644
index 552401f..0000000
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm
+++ /dev/null
@@ -1,241 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
-
-#include <stddef.h>
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "chrome/browser/ui/cocoa/test/cocoa_profile_test.h"
-#include "chrome/browser/ui/cocoa/test/scoped_force_rtl_mac.h"
-#include "chrome/browser/ui/omnibox/chrome_omnibox_client.h"
-#include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h"
-#include "chrome/browser/ui/toolbar/chrome_toolbar_model_delegate.h"
-#include "chrome/test/base/testing_profile.h"
-#include "components/omnibox/browser/omnibox_popup_model.h"
-#include "components/omnibox/browser/omnibox_popup_view.h"
-#include "components/toolbar/toolbar_model_impl.h"
-#include "content/public/common/content_constants.h"
-#include "testing/platform_test.h"
-#include "ui/gfx/font.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/image.h"
-
-namespace {
-
-class MockOmniboxEditModel : public OmniboxEditModel {
- public:
-  MockOmniboxEditModel(OmniboxView* view,
-                       OmniboxEditController* controller,
-                       Profile* profile)
-      : OmniboxEditModel(
-            view,
-            controller,
-            base::WrapUnique(new ChromeOmniboxClient(controller, profile))),
-        up_or_down_count_(0) {}
-
-  void OnUpOrDownKeyPressed(int count) override { up_or_down_count_ = count; }
-
-  int up_or_down_count() const { return up_or_down_count_; }
-
-  void set_up_or_down_count(int count) {
-    up_or_down_count_ = count;
-  }
-
- private:
-  int up_or_down_count_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockOmniboxEditModel);
-};
-
-class MockOmniboxPopupView : public OmniboxPopupView {
- public:
-  MockOmniboxPopupView() : is_open_(false) {}
-  ~MockOmniboxPopupView() override {}
-
-  // Overridden from OmniboxPopupView:
-  bool IsOpen() const override { return is_open_; }
-  void InvalidateLine(size_t line) override {}
-  void OnLineSelected(size_t line) override {}
-  void UpdatePopupAppearance() override {}
-  void OnMatchIconUpdated(size_t match_index) override {}
-  void PaintUpdatesNow() override {}
-  void OnDragCanceled() override {}
-
-  void set_is_open(bool is_open) { is_open_ = is_open; }
-
- private:
-  bool is_open_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockOmniboxPopupView);
-};
-
-class TestingToolbarModelDelegate : public ChromeToolbarModelDelegate {
- public:
-  TestingToolbarModelDelegate() {}
-  ~TestingToolbarModelDelegate() override {}
-
-  // Overridden from ChromeToolbarModelDelegate:
-  content::WebContents* GetActiveWebContents() const override { return NULL; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(TestingToolbarModelDelegate);
-};
-
-class TestingOmniboxEditController : public ChromeOmniboxEditController {
- public:
-  explicit TestingOmniboxEditController(ToolbarModel* toolbar_model)
-      : ChromeOmniboxEditController(NULL), toolbar_model_(toolbar_model) {}
-  ~TestingOmniboxEditController() override {}
-
- protected:
-  // Overridden from ChromeOmniboxEditController:
-  void UpdateWithoutTabRestore() override {}
-  void OnChanged() override {}
-  ToolbarModel* GetToolbarModel() override { return toolbar_model_; }
-  const ToolbarModel* GetToolbarModel() const override {
-    return toolbar_model_;
-  }
-  content::WebContents* GetWebContents() override { return nullptr; }
-
- private:
-  ToolbarModel* toolbar_model_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestingOmniboxEditController);
-};
-
-}  // namespace
-
-class OmniboxViewMacTest : public CocoaProfileTest {
- public:
-  void SetModel(OmniboxViewMac* view, OmniboxEditModel* model) {
-    view->model_.reset(model);
-  }
-};
-
-TEST_F(OmniboxViewMacTest, GetFonts) {
-  EXPECT_TRUE(OmniboxViewMac::GetNormalFieldFont());
-  EXPECT_TRUE(OmniboxViewMac::GetBoldFieldFont());
-  EXPECT_TRUE(OmniboxViewMac::GetLargeFont());
-  EXPECT_TRUE(OmniboxViewMac::GetSmallFont());
-}
-
-TEST_F(OmniboxViewMacTest, TabToAutocomplete) {
-  OmniboxViewMac view(NULL, profile(), NULL, NULL);
-
-  // This is deleted by the omnibox view.
-  MockOmniboxEditModel* model =
-      new MockOmniboxEditModel(&view, NULL, profile());
-  SetModel(&view, model);
-
-  MockOmniboxPopupView popup_view;
-  OmniboxPopupModel popup_model(&popup_view, model);
-
-  // With popup closed verify that tab doesn't autocomplete.
-  popup_view.set_is_open(false);
-  view.OnDoCommandBySelector(@selector(insertTab:));
-  EXPECT_EQ(0, model->up_or_down_count());
-  view.OnDoCommandBySelector(@selector(insertBacktab:));
-  EXPECT_EQ(0, model->up_or_down_count());
-
-  // With popup open verify that tab does autocomplete.
-  popup_view.set_is_open(true);
-  view.OnDoCommandBySelector(@selector(insertTab:));
-  EXPECT_EQ(1, model->up_or_down_count());
-  view.OnDoCommandBySelector(@selector(insertBacktab:));
-  EXPECT_EQ(-1, model->up_or_down_count());
-}
-
-TEST_F(OmniboxViewMacTest, UpDownArrow) {
-  OmniboxViewMac view(NULL, profile(), NULL, NULL);
-
-  // This is deleted by the omnibox view.
-  MockOmniboxEditModel* model =
-      new MockOmniboxEditModel(&view, NULL, profile());
-  SetModel(&view, model);
-
-  MockOmniboxPopupView popup_view;
-  OmniboxPopupModel popup_model(&popup_view, model);
-
-  // With popup closed verify that pressing up and down arrow works.
-  popup_view.set_is_open(false);
-  model->set_up_or_down_count(0);
-  view.OnDoCommandBySelector(@selector(moveDown:));
-  EXPECT_EQ(1, model->up_or_down_count());
-  model->set_up_or_down_count(0);
-  view.OnDoCommandBySelector(@selector(moveUp:));
-  EXPECT_EQ(-1, model->up_or_down_count());
-
-  // With popup open verify that pressing up and down arrow works.
-  popup_view.set_is_open(true);
-  model->set_up_or_down_count(0);
-  view.OnDoCommandBySelector(@selector(moveDown:));
-  EXPECT_EQ(1, model->up_or_down_count());
-  model->set_up_or_down_count(0);
-  view.OnDoCommandBySelector(@selector(moveUp:));
-  EXPECT_EQ(-1, model->up_or_down_count());
-}
-
-TEST_F(OmniboxViewMacTest, WritingDirectionLTR) {
-  TestingToolbarModelDelegate delegate;
-  ToolbarModelImpl toolbar_model(&delegate, 32 * 1024);
-  TestingOmniboxEditController edit_controller(&toolbar_model);
-  OmniboxViewMac view(&edit_controller, profile(), NULL, NULL);
-
-  // This is deleted by the omnibox view.
-  MockOmniboxEditModel* model =
-      new MockOmniboxEditModel(&view, &edit_controller, profile());
-  MockOmniboxPopupView popup_view;
-  OmniboxPopupModel popup_model(&popup_view, model);
-
-  model->OnSetFocus(true);
-  SetModel(&view, model);
-  view.SetUserText(base::ASCIIToUTF16("foo.com"));
-  model->OnChanged();
-
-  base::scoped_nsobject<NSMutableAttributedString> string(
-      [[NSMutableAttributedString alloc] initWithString:@"foo.com"]);
-  view.ApplyTextStyle(string);
-
-  NSParagraphStyle* paragraphStyle =
-      [string attribute:NSParagraphStyleAttributeName
-                 atIndex:0
-          effectiveRange:NULL];
-  DCHECK(paragraphStyle);
-  EXPECT_EQ(paragraphStyle.alignment, NSLeftTextAlignment);
-  EXPECT_EQ(paragraphStyle.baseWritingDirection, NSWritingDirectionLeftToRight);
-}
-
-TEST_F(OmniboxViewMacTest, WritingDirectionRTL) {
-  cocoa_l10n_util::ScopedForceRTLMac rtl;
-
-  TestingToolbarModelDelegate delegate;
-  ToolbarModelImpl toolbar_model(&delegate, 32 * 1024);
-  TestingOmniboxEditController edit_controller(&toolbar_model);
-  OmniboxViewMac view(&edit_controller, profile(), NULL, NULL);
-
-  // This is deleted by the omnibox view.
-  MockOmniboxEditModel* model =
-      new MockOmniboxEditModel(&view, &edit_controller, profile());
-  MockOmniboxPopupView popup_view;
-  OmniboxPopupModel popup_model(&popup_view, model);
-
-  model->OnSetFocus(true);
-  SetModel(&view, model);
-  view.SetUserText(base::ASCIIToUTF16("foo.com"));
-  model->OnChanged();
-
-  base::scoped_nsobject<NSMutableAttributedString> string(
-      [[NSMutableAttributedString alloc] initWithString:@"foo.com"]);
-  view.ApplyTextStyle(string);
-
-  NSParagraphStyle* paragraphStyle =
-      [string attribute:NSParagraphStyleAttributeName
-                 atIndex:0
-          effectiveRange:NULL];
-  DCHECK(paragraphStyle);
-  EXPECT_EQ(paragraphStyle.alignment, NSRightTextAlignment);
-  EXPECT_EQ(paragraphStyle.baseWritingDirection, NSWritingDirectionLeftToRight);
-}
diff --git a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm
index 7736dcc..f62a9ad7 100644
--- a/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm
+++ b/chrome/browser/ui/cocoa/permission_bubble/permission_bubble_cocoa_interactive_uitest.mm
@@ -15,7 +15,6 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_window.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/interactive_test_utils.h"
diff --git a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm
index 70c5e81..a73ad31 100644
--- a/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm
+++ b/chrome/browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm
@@ -10,7 +10,6 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/cocoa/browser_window_cocoa.h"
 #include "chrome/browser/ui/cocoa/browser_window_controller.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.h b/chrome/browser/ui/cocoa/status_bubble_mac.h
deleted file mode 100644
index 8c03a306..0000000
--- a/chrome/browser/ui/cocoa/status_bubble_mac.h
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_
-#define CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_
-
-#include <string>
-
-#import <Cocoa/Cocoa.h>
-#import <QuartzCore/QuartzCore.h>
-#include <stdint.h>
-
-#include "base/compiler_specific.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "chrome/browser/ui/status_bubble.h"
-#include "url/gurl.h"
-
-namespace gfx {
-class Point;
-}
-
-class StatusBubbleMacTest;
-@class StatusBubbleWindow;
-
-class StatusBubbleMac : public StatusBubble {
- public:
-  // The various states that a status bubble may be in.  Public for delegate
-  // access (for testing).
-  enum StatusBubbleState {
-    kBubbleHidden,         // Fully hidden
-    kBubbleShowingTimer,   // Waiting to fade in
-    kBubbleShowingFadeIn,  // In a fade-in transition
-    kBubbleShown,          // Fully visible
-    kBubbleHidingTimer,    // Waiting to fade out
-    kBubbleHidingFadeOut   // In a fade-out transition
-  };
-
-  StatusBubbleMac(NSWindow* parent, id delegate);
-  ~StatusBubbleMac() override;
-
-  // StatusBubble implementation.
-  void SetStatus(const base::string16& status) override;
-  void SetURL(const GURL& url) override;
-  void Hide() override;
-  void MouseMoved(bool left_content) override;
-  void UpdateDownloadShelfVisibility(bool visible) override;
-
-  // Mac-specific method: Update the size and position of the status bubble to
-  // match the parent window. Safe to call even when the status bubble does not
-  // exist.
-  void UpdateSizeAndPosition();
-
-  // Mac-specific method: Change the parent window of the status bubble. Safe to
-  // call even when the status bubble does not exist.
-  void SwitchParentWindow(NSWindow* parent);
-
-  // Expand the bubble to fit a URL too long for the standard bubble size.
-  void ExpandBubble();
-
- protected:
-  // Get the current location of the mouse. Protected so that it can be
-  // stubbed out for testing.
-  virtual gfx::Point GetMouseLocation();
-
-  // Notify mouse events with current mouse location. The location is (0,0) when
-  // mouse is at the bottom-left of the screen.
-  void MouseMovedAt(const gfx::Point& location, bool left_content);
-
- private:
-  friend class StatusBubbleMacTest;
-
-  // Setter for state_.  Use this instead of writing to state_ directly so
-  // that state changes can be observed by unit tests.
-  void SetState(StatusBubbleState state);
-
-  // Sets the bubble text for SetStatus and SetURL.
-  void SetText(const base::string16& text, bool is_url);
-
-  // Construct the window/widget if it does not already exist. (Safe to call if
-  // it does.)
-  void Create();
-
-  // Attaches the status bubble window to its parent window. Safe to call even
-  // when already attached.
-  void Attach();
-
-  // Detaches the status bubble window from its parent window.
-  void Detach();
-
-  // Is the status bubble attached to the browser window? It should be attached
-  // when shown and during any fades, but should be detached when hidden.
-  bool is_attached();
-
-  // Begins fading the status bubble window in or out depending on the value
-  // of |show|.  This must be called from the appropriate fade state,
-  // kBubbleShowingFadeIn or kBubbleHidingFadeOut, or from the appropriate
-  // fully-shown/hidden state, kBubbleShown or kBubbleHidden.  This may be
-  // called at any point during a fade-in or fade-out; it is even possible to
-  // reverse a transition before it has completed.
-  void Fade(bool show);
-
-  // Starts an animation of the bubble window to a specific alpha value over a
-  // specific period of time.
-  void AnimateWindowAlpha(CGFloat alpha, NSTimeInterval duration);
-
-  // Method called from the completion callbacks when a fade-in or fade-out
-  // transition has completed.
-  void AnimationDidStop();
-
-  // One-shot timer operations to manage the delays associated with the
-  // kBubbleShowingTimer and kBubbleHidingTimer states.  StartTimer and
-  // TimerFired must be called from one of these states.  StartTimer may be
-  // called while the timer is still running; in that case, the timer will be
-  // reset. CancelTimer may be called from any state.
-  void StartTimer(int64_t time_ms);
-  void CancelTimer();
-  void TimerFired();
-
-  // Begin the process of showing or hiding the status bubble.  These may be
-  // called from any state, and will take the appropriate action to initiate
-  // any state changes that may be needed.
-  void StartShowing();
-  void StartHiding();
-
-  // Cancel the expansion timer.
-  void CancelExpandTimer();
-
-  // Sets the frame of the status bubble window to |window_frame|, adjusting
-  // for the given mouse position if necessary. Protected for use in tests.
-  void SetFrameAvoidingMouse(NSRect window_frame, const gfx::Point& mouse_pos);
-
-  // Calculate the appropriate frame for the status bubble window. If
-  // |expanded_width|, use entire width of parent frame.
-  NSRect CalculateWindowFrame(bool expanded_width);
-
-  // Returns the flags to be used to round the corners of the status bubble.
-  // Before 10.7, windows have square bottom corners, but in 10.7, the bottom
-  // corners are rounded. This method considers the bubble's placement (as
-  // proposed in window_frame) relative to its parent window in determining
-  // which flags to return. This function may choose to round any corner,
-  // including top corners. Note that there may be other reasons that a
-  // status bubble's corner may be rounded in addition to those dependent on
-  // OS version, and flags will be set or unset elsewhere to address these
-  // concerns.
-  unsigned long OSDependentCornerFlags(NSRect window_frame);
-
-  // Returns the status bubble window as an NSWindow. For use in tests.
-  NSWindow* GetWindow();
-
-  // The window we attach ourselves to.
-  NSWindow* parent_;  // WEAK
-
-  // The object that we query about our vertical offset for positioning.
-  id delegate_;  // WEAK
-
-  // The window we own.
-  base::scoped_nsobject<StatusBubbleWindow> window_;
-
-  // The status text we want to display when there are no URLs to display.
-  NSString* status_text_;
-
-  // The url we want to display when there is no status text to display.
-  NSString* url_text_;
-
-  // The status bubble's current state.  Do not write to this field directly;
-  // use SetState().
-  StatusBubbleState state_;
-
-  // True if operations are to be performed immediately rather than waiting
-  // for delays and transitions.  Normally false, this should only be set to
-  // true for testing.
-  bool immediate_;
-
-  // True if the status bubble has been expanded. If the bubble is in the
-  // expanded state and encounters a new URL, change size immediately,
-  // with no hover delay.
-  bool is_expanded_;
-
-  // The original, non-elided URL.
-  GURL url_;
-
-  // The factory used to generate weak pointers for the show and hide delay
-  // timers.
-  base::WeakPtrFactory<StatusBubbleMac> timer_factory_;
-
-  // The factory used to generate weak pointers for the expansion delay timer.
-  base::WeakPtrFactory<StatusBubbleMac> expand_timer_factory_;
-
-  // The factory used to generate weak pointers for the CAAnimation completion
-  // handlers.
-  base::WeakPtrFactory<StatusBubbleMac> completion_handler_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(StatusBubbleMac);
-};
-
-// Delegate interface
-@interface NSObject(StatusBubbleDelegate)
-// Called to query the delegate about the frame StatusBubble should position
-// itself in. Frame is returned in the parent window coordinates.
-- (NSRect)statusBubbleBaseFrame;
-
-// Called from SetState to notify the delegate of state changes.
-- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_STATUS_BUBBLE_MAC_H_
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac.mm b/chrome/browser/ui/cocoa/status_bubble_mac.mm
deleted file mode 100644
index a519186d..0000000
--- a/chrome/browser/ui/cocoa/status_bubble_mac.mm
+++ /dev/null
@@ -1,800 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/cocoa/status_bubble_mac.h"
-
-#include <limits>
-
-#include "base/bind.h"
-#include "base/compiler_specific.h"
-#include "base/debug/stack_trace.h"
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_block.h"
-#include "base/mac/sdk_forward_declarations.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#import "chrome/browser/ui/cocoa/bubble_view.h"
-#include "chrome/browser/ui/cocoa/cocoa_util.h"
-#include "components/url_formatter/elide_url.h"
-#include "components/url_formatter/url_formatter.h"
-#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSAnimation+Duration.h"
-#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSBezierPath+RoundRect.h"
-#import "third_party/google_toolbox_for_mac/src/AppKit/GTMNSColor+Luminance.h"
-#include "ui/base/cocoa/cocoa_base_utils.h"
-#include "ui/base/cocoa/window_size_constants.h"
-#include "ui/gfx/font_list.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/platform_font.h"
-#include "ui/gfx/text_elider.h"
-#include "ui/gfx/text_utils.h"
-
-namespace {
-
-const int kStatusBubbleWindowHeight = 18;
-
-// The width of the bubble in relation to the width of the parent window.
-const CGFloat kStatusBubbleWindowWidthPercent = 1.0 / 3.0;
-
-// How close the mouse can get to the infobubble before it starts sliding
-// off-screen.
-const int kMousePadding = 20;
-
-const int kTextPadding = 3;
-
-// The status bubble's maximum opacity, when fully faded in.
-const CGFloat kBubbleOpacity = 1.0;
-
-// Delay before showing or hiding the bubble after a SetStatus or SetURL call.
-const int64_t kShowDelayMS = 80;
-const int64_t kHideDelayMS = 250;
-
-// How long each fade should last.
-const NSTimeInterval kShowFadeInDurationSeconds = 0.120;
-const NSTimeInterval kHideFadeOutDurationSeconds = 0.200;
-
-// How quickly the status bubble should expand.
-const CGFloat kExpansionDurationSeconds = 0.125;
-
-}  // namespace
-
-// StatusBubbleWindow becomes a child of |statusBubbleParentWindow|, but waits
-// until |statusBubbleParentWindow| is visible. This works around macOS
-// bugs/features which make unexpected things happen when adding a child window
-// to a window that's in another space, miniaturized, or hidden
-// (https://crbug.com/783521, https://crbug.com/798792).
-@interface StatusBubbleWindow : NSWindow
-
-// The window which this window should become a child of. May be changed or
-// nilled out at any time.
-@property(assign, nonatomic) NSWindow* statusBubbleParentWindow;
-
-@end
-
-@implementation StatusBubbleWindow {
-  BOOL observingParentWindowVisibility_;
-}
-@synthesize statusBubbleParentWindow = statusBubbleParentWindow_;
-
-- (void)dealloc {
-  // StatusBubbleMac is expected to always clear statusBubbleParentWindow
-  // before releasing StatusBubbleWindow. If that changes, it's OK to remove
-  // this DCHECK as long as StatusBubbleWindow will never outlive its parent.
-  DCHECK(!statusBubbleParentWindow_);
-
-  [self stopObserving];
-  [super dealloc];
-}
-
-- (void)setStatusBubbleParentWindow:(NSWindow*)statusBubbleParentWindow {
-  if (statusBubbleParentWindow_ == statusBubbleParentWindow)
-    return;
-
-  // First, detach from the current parent window, if any.
-  if (statusBubbleParentWindow_) {
-    [self stopObserving];
-    [self orderOut:nil];  // Also removes |self| from its parent window.
-  }
-
-  // Assign the new parent window.
-  statusBubbleParentWindow_ = statusBubbleParentWindow;
-
-  if (statusBubbleParentWindow_) {
-    // Attach to the new parent window if it's visible and on the active space.
-    [self maybeAttach];
-
-    if (!self.parentWindow) {
-      // If maybeAttach bailed, start observing the window's visibility and the
-      // active space, and try again when they change.
-      observingParentWindowVisibility_ = YES;
-      [statusBubbleParentWindow_ addObserver:self
-                                  forKeyPath:@"visible"
-                                     options:0
-                                     context:nil];
-      [[NSWorkspace sharedWorkspace].notificationCenter
-          addObserver:self
-             selector:@selector(maybeAttach)
-                 name:NSWorkspaceActiveSpaceDidChangeNotification
-               object:[NSWorkspace sharedWorkspace]];
-    }
-  }
-}
-
-- (void)stopObserving {
-  if (!observingParentWindowVisibility_)
-    return;
-  observingParentWindowVisibility_ = NO;
-  [statusBubbleParentWindow_ removeObserver:self
-                                 forKeyPath:@"visible"
-                                    context:nil];
-  [[NSWorkspace sharedWorkspace].notificationCenter removeObserver:self];
-}
-
-- (void)maybeAttach {
-  if (![statusBubbleParentWindow_ isVisible])
-    return;
-  if (![statusBubbleParentWindow_ isOnActiveSpace])
-    return;
-  [self stopObserving];
-  // Adding |self| as a child window also orders it in.
-  [statusBubbleParentWindow_ addChildWindow:self ordered:NSWindowAbove];
-}
-
-- (void)observeValueForKeyPath:(NSString*)keyPath
-                      ofObject:(id)object
-                        change:(NSDictionary<NSKeyValueChangeKey, id>*)change
-                       context:(void*)context {
-  [self maybeAttach];
-}
-
-@end
-
-StatusBubbleMac::StatusBubbleMac(NSWindow* parent, id delegate)
-    : parent_(parent),
-      delegate_(delegate),
-      status_text_(nil),
-      url_text_(nil),
-      state_(kBubbleHidden),
-      immediate_(false),
-      is_expanded_(false),
-      timer_factory_(this),
-      expand_timer_factory_(this),
-      completion_handler_factory_(this) {
-  Create();
-}
-
-StatusBubbleMac::~StatusBubbleMac() {
-  DCHECK(window_);
-
-  Hide();
-
-  completion_handler_factory_.InvalidateWeakPtrs();
-  Detach();
-}
-
-void StatusBubbleMac::SetStatus(const base::string16& status) {
-  SetText(status, false);
-}
-
-void StatusBubbleMac::SetURL(const GURL& url) {
-  url_ = url;
-
-  CGFloat bubble_width = NSWidth([window_ frame]);
-  if (state_ == kBubbleHidden)
-    bubble_width = NSWidth(CalculateWindowFrame(/*expand=*/false));
-  int text_width = static_cast<int>(bubble_width -
-                                    kBubbleViewTextPositionX -
-                                    kTextPadding);
-
-  // Scale from view to window coordinates before eliding URL string.
-  NSSize scaled_width = NSMakeSize(text_width, 0);
-  scaled_width = [[parent_ contentView] convertSize:scaled_width fromView:nil];
-  text_width = static_cast<int>(scaled_width.width);
-  NSFont* font = [[window_ contentView] font];
-  gfx::FontList font_list_chr(
-      gfx::Font(gfx::PlatformFont::CreateFromNativeFont(font)));
-
-  base::string16 original_url_text = url_formatter::FormatUrl(url);
-  base::string16 status = url_formatter::ElideUrl(
-      url, font_list_chr, text_width, gfx::Typesetter::BROWSER);
-
-  SetText(status, true);
-
-  // In testing, don't use animation. When ExpandBubble is tested, it is
-  // called explicitly.
-  if (immediate_)
-    return;
-  else
-    CancelExpandTimer();
-
-  // If the bubble has been expanded, the user has already hovered over a link
-  // to trigger the expanded state.  Don't wait to change the bubble in this
-  // case -- immediately expand or contract to fit the URL.
-  if (is_expanded_ && !url.is_empty()) {
-    ExpandBubble();
-  } else if (original_url_text.length() > status.length()) {
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, base::Bind(&StatusBubbleMac::ExpandBubble,
-                              expand_timer_factory_.GetWeakPtr()),
-        base::TimeDelta::FromMilliseconds(kExpandHoverDelayMS));
-  }
-}
-
-void StatusBubbleMac::SetText(const base::string16& text, bool is_url) {
-  // The status bubble allows the status and URL strings to be set
-  // independently.  Whichever was set non-empty most recently will be the
-  // value displayed.  When both are empty, the status bubble hides.
-
-  NSString* text_ns = base::SysUTF16ToNSString(text);
-
-  NSString** main;
-  NSString** backup;
-
-  if (is_url) {
-    main = &url_text_;
-    backup = &status_text_;
-  } else {
-    main = &status_text_;
-    backup = &url_text_;
-  }
-
-  // Don't return from this function early.  It's important to make sure that
-  // all calls to StartShowing and StartHiding are made, so that all delays
-  // are observed properly.  Specifically, if the state is currently
-  // kBubbleShowingTimer, the timer will need to be restarted even if
-  // [text_ns isEqualToString:*main] is true.
-
-  [*main autorelease];
-  *main = [text_ns retain];
-
-  bool show = true;
-  if ([*main length] > 0)
-    [[window_ contentView] setContent:*main];
-  else if ([*backup length] > 0)
-    [[window_ contentView] setContent:*backup];
-  else
-    show = false;
-
-  if (show) {
-    // Call StartShowing() first to update the current bubble state before
-    // calculating a new size.
-    StartShowing();
-    UpdateSizeAndPosition();
-  } else {
-    StartHiding();
-  }
-}
-
-void StatusBubbleMac::Hide() {
-  CancelTimer();
-  CancelExpandTimer();
-  is_expanded_ = false;
-
-  bool fade_out = false;
-  if (state_ == kBubbleHidingFadeOut || state_ == kBubbleShowingFadeIn) {
-    SetState(kBubbleHidingFadeOut);
-
-    if (!immediate_) {
-      // An animation is in progress.  Cancel it by starting a new animation.
-      // Use cocoa_util::kMinimumTimeInterval to set the opacity as rapidly as
-      // possible.
-      fade_out = true;
-      AnimateWindowAlpha(0.0, cocoa_util::kMinimumTimeInterval);
-    }
-  }
-
-  NSRect frame = CalculateWindowFrame(/*expand=*/false);
-  if (!fade_out) {
-    // No animation is in progress, so the opacity can be set directly.
-    [window_ setAlphaValue:0.0];
-    SetState(kBubbleHidden);
-    frame.size = ui::kWindowSizeDeterminedLater.size;
-  }
-
-  // Stop any width animation and reset the bubble size.
-  if (!immediate_) {
-    [NSAnimationContext beginGrouping];
-    [[NSAnimationContext currentContext]
-        setDuration:cocoa_util::kMinimumTimeInterval];
-    [[window_ animator] setFrame:frame display:NO];
-    [NSAnimationContext endGrouping];
-  } else {
-    [window_ setFrame:frame display:NO];
-  }
-
-  [status_text_ release];
-  status_text_ = nil;
-  [url_text_ release];
-  url_text_ = nil;
-}
-
-void StatusBubbleMac::SetFrameAvoidingMouse(
-    NSRect window_frame, const gfx::Point& mouse_pos) {
-  if (!window_)
-    return;
-
-  // Bubble's base rect in |parent_| (window base) coordinates.
-  NSRect base_rect;
-  if ([delegate_ respondsToSelector:@selector(statusBubbleBaseFrame)]) {
-    base_rect = [delegate_ statusBubbleBaseFrame];
-  } else {
-    base_rect = [[parent_ contentView] bounds];
-    base_rect = [[parent_ contentView] convertRect:base_rect toView:nil];
-  }
-
-  // To start, assume default positioning in the lower left corner.
-  // The window_frame position is in global (screen) coordinates.
-  window_frame.origin =
-      ui::ConvertPointFromWindowToScreen(parent_, base_rect.origin);
-
-  // Get the cursor position relative to the top right corner of the bubble.
-  gfx::Point relative_pos(mouse_pos.x() - NSMaxX(window_frame),
-                          mouse_pos.y() - NSMaxY(window_frame));
-
-  // If the mouse is in a position where we think it would move the
-  // status bubble, figure out where and how the bubble should be moved, and
-  // what sorts of corners it should have.
-  unsigned long corner_flags;
-  if (relative_pos.y() < kMousePadding &&
-      relative_pos.x() < kMousePadding) {
-    int offset = kMousePadding - relative_pos.y();
-
-    // Make the movement non-linear.
-    offset = offset * offset / kMousePadding;
-
-    // When the mouse is entering from the right, we want the offset to be
-    // scaled by how horizontally far away the cursor is from the bubble.
-    if (relative_pos.x() > 0) {
-      offset *= (kMousePadding - relative_pos.x()) / kMousePadding;
-    }
-
-    bool is_on_screen = true;
-    NSScreen* screen = [window_ screen];
-    if (screen &&
-        NSMinY([screen visibleFrame]) > NSMinY(window_frame) - offset) {
-      is_on_screen = false;
-    }
-
-    // If something is shown below tab contents (devtools, download shelf etc.),
-    // adjust the position to sit on top of it.
-    bool is_any_shelf_visible = NSMinY(base_rect) > 0;
-
-    if (is_on_screen && !is_any_shelf_visible) {
-      // Cap the offset and change the visual presentation of the bubble
-      // depending on where it ends up (so that rounded corners square off
-      // and mate to the edges of the tab content).
-      if (offset >= NSHeight(window_frame)) {
-        offset = NSHeight(window_frame);
-        corner_flags = kRoundedBottomLeftCorner | kRoundedBottomRightCorner;
-      } else if (offset > 0) {
-        corner_flags = kRoundedTopRightCorner |
-                       kRoundedBottomLeftCorner |
-                       kRoundedBottomRightCorner;
-      } else {
-        corner_flags = kRoundedTopRightCorner;
-      }
-
-      // Place the bubble on the left, but slightly lower.
-      window_frame.origin.y -= offset;
-    } else {
-      // Cannot move the bubble down without obscuring other content.
-      // Move it to the far right instead.
-      corner_flags = kRoundedTopLeftCorner;
-      window_frame.origin.x += NSWidth(base_rect) - NSWidth(window_frame);
-    }
-  } else {
-    // Use the default position in the lower left corner of the content area.
-    corner_flags = kRoundedTopRightCorner;
-  }
-
-  corner_flags |= OSDependentCornerFlags(window_frame);
-
-  BubbleView* contentView =
-      base::mac::ObjCCast<BubbleView>([window_ contentView]);
-  [contentView setCornerFlags:corner_flags];
-  [window_ setFrame:window_frame display:YES];
-}
-
-void StatusBubbleMac::MouseMoved(bool left_content) {
-  MouseMovedAt(gfx::Point([NSEvent mouseLocation]), left_content);
-}
-
-void StatusBubbleMac::MouseMovedAt(
-    const gfx::Point& location, bool left_content) {
-  if (!left_content)
-    SetFrameAvoidingMouse([window_ frame], location);
-}
-
-void StatusBubbleMac::UpdateDownloadShelfVisibility(bool visible) {
-  UpdateSizeAndPosition();
-}
-
-void StatusBubbleMac::Create() {
-  DCHECK(!window_);
-
-  window_.reset([[StatusBubbleWindow alloc]
-      initWithContentRect:ui::kWindowSizeDeterminedLater
-                styleMask:NSBorderlessWindowMask
-                  backing:NSBackingStoreBuffered
-                    defer:NO]);
-  [window_ setCollectionBehavior:[window_ collectionBehavior] |
-                                 NSWindowCollectionBehaviorTransient];
-  [window_ setMovableByWindowBackground:NO];
-  [window_ setBackgroundColor:[NSColor clearColor]];
-  [window_ setOpaque:NO];
-  [window_ setHasShadow:NO];
-
-  base::scoped_nsobject<BubbleView> view(
-      [[BubbleView alloc] initWithFrame:NSZeroRect]);
-  [window_ setContentView:view];
-
-  [window_ setAlphaValue:0.0];
-
-  // TODO(dtseng): Ignore until we provide NSAccessibility support.
-  [window_ accessibilitySetOverrideValue:NSAccessibilityUnknownRole
-                            forAttribute:NSAccessibilityRoleAttribute];
-
-  [view setCornerFlags:kRoundedTopRightCorner];
-  MouseMovedAt(gfx::Point(), false);
-}
-
-void StatusBubbleMac::Attach() {
-  if (is_attached())
-    return;
-  [window_ setStatusBubbleParentWindow:parent_];
-  [[window_ contentView] setThemeProvider:parent_];
-}
-
-void StatusBubbleMac::Detach() {
-  if (!is_attached())
-    return;
-
-  // Magic setFrame: See http://crbug.com/58506 and http://crrev.com/3564021 .
-  // TODO(rohitrao): Does the frame size actually matter here?  Can we always
-  // set it to kWindowSizeDeterminedLater?
-  NSRect frame = [window_ frame];
-  frame.size = ui::kWindowSizeDeterminedLater.size;
-  if (state_ != kBubbleHidden) {
-    frame = CalculateWindowFrame(/*expand=*/false);
-  }
-  // See https://crbug.com/28107 and https://crbug.com/29054.
-  [window_ setFrame:frame display:NO];
-  [window_ setStatusBubbleParentWindow:nil];
-
-  [[window_ contentView] setThemeProvider:nil];
-}
-
-bool StatusBubbleMac::is_attached() {
-  return [window_ statusBubbleParentWindow] != nil;
-}
-
-void StatusBubbleMac::AnimationDidStop() {
-  DCHECK([NSThread isMainThread]);
-  DCHECK(state_ == kBubbleShowingFadeIn || state_ == kBubbleHidingFadeOut);
-  DCHECK(is_attached());
-
-  if (state_ == kBubbleShowingFadeIn) {
-    DCHECK_EQ([[window_ animator] alphaValue], kBubbleOpacity);
-    SetState(kBubbleShown);
-  } else {
-    DCHECK_EQ([[window_ animator] alphaValue], 0.0);
-    SetState(kBubbleHidden);
-  }
-}
-
-void StatusBubbleMac::SetState(StatusBubbleState state) {
-  if (state == state_)
-    return;
-
-  if (state == kBubbleHidden) {
-    is_expanded_ = false;
-    Detach();
-  } else {
-    Attach();
-  }
-
-  if ([delegate_ respondsToSelector:@selector(statusBubbleWillEnterState:)])
-    [delegate_ statusBubbleWillEnterState:state];
-
-  state_ = state;
-}
-
-void StatusBubbleMac::Fade(bool show) {
-  DCHECK([NSThread isMainThread]);
-
-  StatusBubbleState fade_state = kBubbleShowingFadeIn;
-  StatusBubbleState target_state = kBubbleShown;
-  NSTimeInterval full_duration = kShowFadeInDurationSeconds;
-  CGFloat opacity = kBubbleOpacity;
-
-  if (!show) {
-    fade_state = kBubbleHidingFadeOut;
-    target_state = kBubbleHidden;
-    full_duration = kHideFadeOutDurationSeconds;
-    opacity = 0.0;
-  }
-
-  DCHECK(state_ == fade_state || state_ == target_state);
-
-  if (state_ == target_state)
-    return;
-
-  if (immediate_) {
-    [window_ setAlphaValue:opacity];
-    SetState(target_state);
-    return;
-  }
-
-  // If an incomplete transition has left the opacity somewhere between 0 and
-  // kBubbleOpacity, the fade rate is kept constant by shortening the duration.
-  NSTimeInterval duration =
-      full_duration *
-      fabs(opacity - [[window_ animator] alphaValue]) / kBubbleOpacity;
-
-  // 0.0 will not cancel an in-progress animation.
-  if (duration == 0.0)
-    duration = cocoa_util::kMinimumTimeInterval;
-
-  // Cancel an in-progress transition and replace it with this fade.
-  AnimateWindowAlpha(opacity, duration);
-}
-
-void StatusBubbleMac::AnimateWindowAlpha(CGFloat alpha,
-                                         NSTimeInterval duration) {
-  completion_handler_factory_.InvalidateWeakPtrs();
-  base::WeakPtr<StatusBubbleMac> weak_ptr(
-      completion_handler_factory_.GetWeakPtr());
-  [NSAnimationContext runAnimationGroup:^(NSAnimationContext* context) {
-    [context setDuration:duration];
-    [[window_ animator] setAlphaValue:alpha];
-  }
-      completionHandler:^{
-        if (weak_ptr)
-          weak_ptr->AnimationDidStop();
-      }];
-}
-
-void StatusBubbleMac::StartTimer(int64_t delay_ms) {
-  DCHECK([NSThread isMainThread]);
-  DCHECK(state_ == kBubbleShowingTimer || state_ == kBubbleHidingTimer);
-
-  if (immediate_) {
-    TimerFired();
-    return;
-  }
-
-  // There can only be one running timer.
-  CancelTimer();
-
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE,
-      base::Bind(&StatusBubbleMac::TimerFired, timer_factory_.GetWeakPtr()),
-      base::TimeDelta::FromMilliseconds(delay_ms));
-}
-
-void StatusBubbleMac::CancelTimer() {
-  DCHECK([NSThread isMainThread]);
-
-  if (timer_factory_.HasWeakPtrs())
-    timer_factory_.InvalidateWeakPtrs();
-}
-
-void StatusBubbleMac::TimerFired() {
-  DCHECK(state_ == kBubbleShowingTimer || state_ == kBubbleHidingTimer);
-  DCHECK([NSThread isMainThread]);
-
-  if (state_ == kBubbleShowingTimer) {
-    SetState(kBubbleShowingFadeIn);
-    Fade(true);
-  } else {
-    SetState(kBubbleHidingFadeOut);
-    Fade(false);
-  }
-}
-
-void StatusBubbleMac::StartShowing() {
-  if (state_ == kBubbleHidden) {
-    // Arrange to begin fading in after a delay.
-    SetState(kBubbleShowingTimer);
-    StartTimer(kShowDelayMS);
-  } else if (state_ == kBubbleHidingFadeOut) {
-    // Cancel the fade-out in progress and replace it with a fade in.
-    SetState(kBubbleShowingFadeIn);
-    Fade(true);
-  } else if (state_ == kBubbleHidingTimer) {
-    // The bubble was already shown but was waiting to begin fading out.  It's
-    // given a stay of execution.
-    SetState(kBubbleShown);
-    CancelTimer();
-  } else if (state_ == kBubbleShowingTimer) {
-    // The timer was already running but nothing was showing yet.  Reaching
-    // this point means that there is a new request to show something.  Start
-    // over again by resetting the timer, effectively invalidating the earlier
-    // request.
-    StartTimer(kShowDelayMS);
-  }
-
-  // If the state is kBubbleShown or kBubbleShowingFadeIn, leave everything
-  // alone.
-}
-
-void StatusBubbleMac::StartHiding() {
-  if (state_ == kBubbleShown) {
-    // Arrange to begin fading out after a delay.
-    SetState(kBubbleHidingTimer);
-    StartTimer(kHideDelayMS);
-  } else if (state_ == kBubbleShowingFadeIn) {
-    // Cancel the fade-in in progress and replace it with a fade out.
-    SetState(kBubbleHidingFadeOut);
-    Fade(false);
-  } else if (state_ == kBubbleShowingTimer) {
-    // The bubble was already hidden but was waiting to begin fading in.  Too
-    // bad, it won't get the opportunity now.
-    SetState(kBubbleHidden);
-    CancelTimer();
-  }
-
-  // If the state is kBubbleHidden, kBubbleHidingFadeOut, or
-  // kBubbleHidingTimer, leave everything alone.  The timer is not reset as
-  // with kBubbleShowingTimer in StartShowing() because a subsequent request
-  // to hide something while one is already in flight does not invalidate the
-  // earlier request.
-}
-
-void StatusBubbleMac::CancelExpandTimer() {
-  DCHECK([NSThread isMainThread]);
-  expand_timer_factory_.InvalidateWeakPtrs();
-}
-
-// Get the current location of the mouse in screen coordinates. To make this
-// class testable, all code should use this method rather than using
-// NSEvent mouseLocation directly.
-gfx::Point StatusBubbleMac::GetMouseLocation() {
-  NSPoint p = [NSEvent mouseLocation];
-  --p.y;  // The docs say the y coord starts at 1 not 0; don't ask why.
-  return gfx::Point(p.x, p.y);
-}
-
-void StatusBubbleMac::ExpandBubble() {
-  // Calculate the width available for expanded and standard bubbles.
-  NSRect window_frame = CalculateWindowFrame(/*expand=*/true);
-  CGFloat max_bubble_width = NSWidth(window_frame);
-  CGFloat standard_bubble_width =
-      NSWidth(CalculateWindowFrame(/*expand=*/false));
-
-  // Generate the URL string that fits in the expanded bubble.
-  NSFont* font = [[window_ contentView] font];
-  gfx::FontList font_list_chr(
-      gfx::Font(gfx::PlatformFont::CreateFromNativeFont(font)));
-  base::string16 expanded_url = url_formatter::ElideUrl(
-      url_, font_list_chr, max_bubble_width, gfx::Typesetter::BROWSER);
-
-  // Scale width from gfx::Font in view coordinates to window coordinates.
-  int required_width_for_string =
-      gfx::GetStringWidth(expanded_url, font_list_chr,
-                          gfx::Typesetter::NATIVE) +
-      kTextPadding * 2 + kBubbleViewTextPositionX;
-  NSSize scaled_width = NSMakeSize(required_width_for_string, 0);
-  scaled_width = [[parent_ contentView] convertSize:scaled_width toView:nil];
-  required_width_for_string = scaled_width.width;
-
-  // The expanded width must be at least as wide as the standard width, but no
-  // wider than the maximum width for its parent frame.
-  int expanded_bubble_width =
-      std::max(standard_bubble_width,
-               std::min(max_bubble_width,
-                        static_cast<CGFloat>(required_width_for_string)));
-
-  SetText(expanded_url, true);
-  is_expanded_ = true;
-  window_frame.size.width = expanded_bubble_width;
-
-  // In testing, don't do any animation.
-  if (immediate_) {
-    [window_ setFrame:window_frame display:YES];
-    return;
-  }
-
-  NSRect actual_window_frame = [window_ frame];
-  // Adjust status bubble origin if bubble was moved to the right.
-  // TODO(alekseys): fix for RTL.
-  if (NSMinX(actual_window_frame) > NSMinX(window_frame)) {
-    actual_window_frame.origin.x =
-        NSMaxX(actual_window_frame) - NSWidth(window_frame);
-  }
-  actual_window_frame.size.width = NSWidth(window_frame);
-
-  // Do not expand if it's going to cover mouse location.
-  gfx::Point p = GetMouseLocation();
-  if (NSPointInRect(NSMakePoint(p.x(), p.y()), actual_window_frame))
-    return;
-
-  // Get the current corner flags and see what needs to change based on the
-  // expansion.
-  BubbleView* contentView =
-      base::mac::ObjCCast<BubbleView>([window_ contentView]);
-  unsigned long corner_flags = [contentView cornerFlags];
-  corner_flags |= OSDependentCornerFlags(actual_window_frame);
-  [contentView setCornerFlags:corner_flags];
-
-  [NSAnimationContext beginGrouping];
-  [[NSAnimationContext currentContext] setDuration:kExpansionDurationSeconds];
-  [[window_ animator] setFrame:actual_window_frame display:YES];
-  [NSAnimationContext endGrouping];
-}
-
-void StatusBubbleMac::UpdateSizeAndPosition() {
-  if (!window_)
-    return;
-
-  // There is no need to update the size if the bubble is hidden.
-  if (state_ == kBubbleHidden)
-    return;
-
-  SetFrameAvoidingMouse(CalculateWindowFrame(/*expand=*/false),
-                        GetMouseLocation());
-}
-
-void StatusBubbleMac::SwitchParentWindow(NSWindow* parent) {
-  DCHECK(parent);
-  Detach();
-  parent_ = parent;
-  Attach();
-  UpdateSizeAndPosition();
-}
-
-NSRect StatusBubbleMac::CalculateWindowFrame(bool expanded_width) {
-  DCHECK(parent_);
-
-  NSRect screenRect;
-  if ([delegate_ respondsToSelector:@selector(statusBubbleBaseFrame)]) {
-    screenRect = [delegate_ statusBubbleBaseFrame];
-    screenRect = [parent_ convertRectToScreen:screenRect];
-  } else {
-    screenRect = [parent_ frame];
-  }
-
-  NSSize size = NSMakeSize(0, kStatusBubbleWindowHeight);
-  size = [[parent_ contentView] convertSize:size toView:nil];
-
-  if (expanded_width) {
-    size.width = screenRect.size.width;
-  } else {
-    size.width = kStatusBubbleWindowWidthPercent * screenRect.size.width;
-  }
-
-  screenRect.size = size;
-  return screenRect;
-}
-
-unsigned long StatusBubbleMac::OSDependentCornerFlags(NSRect window_frame) {
-  unsigned long corner_flags = 0;
-
-  NSRect parent_frame = [parent_ frame];
-
-  // Round the bottom corners when they're right up against the
-  // corresponding edge of the parent window, or when below the parent
-  // window.
-  if (NSMinY(window_frame) <= NSMinY(parent_frame)) {
-    if (NSMinX(window_frame) == NSMinX(parent_frame)) {
-      corner_flags |= kRoundedBottomLeftCorner;
-    }
-
-    if (NSMaxX(window_frame) == NSMaxX(parent_frame)) {
-      corner_flags |= kRoundedBottomRightCorner;
-    }
-  }
-
-  // Round the top corners when the bubble is below the parent window.
-  if (NSMinY(window_frame) < NSMinY(parent_frame)) {
-    corner_flags |= kRoundedTopLeftCorner | kRoundedTopRightCorner;
-  }
-
-  return corner_flags;
-}
-
-NSWindow* StatusBubbleMac::GetWindow() {
-  return window_;
-}
diff --git a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
deleted file mode 100644
index b31159f8..0000000
--- a/chrome/browser/ui/cocoa/status_bubble_mac_unittest.mm
+++ /dev/null
@@ -1,699 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/status_bubble_mac.h"
-
-#include <Cocoa/Cocoa.h>
-
-#include <memory>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/utf_string_conversions.h"
-#import "chrome/browser/ui/cocoa/bubble_view.h"
-#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-#include "ui/gfx/geometry/point.h"
-#include "url/gurl.h"
-
-using base::UTF8ToUTF16;
-
-// The test delegate records all of the status bubble object's state
-// transitions.
-@interface StatusBubbleMacTestDelegate : NSObject {
- @private
-  NSWindow* window_;  // Weak.
-  NSPoint baseFrameOffset_;
-  std::vector<StatusBubbleMac::StatusBubbleState> states_;
-}
-- (id)initWithWindow:(NSWindow*)window;
-- (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset;
-- (NSRect)statusBubbleBaseFrame;
-- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state;
-@end
-@implementation StatusBubbleMacTestDelegate
-- (id)initWithWindow:(NSWindow*)window {
-  if ((self = [super init])) {
-    window_ = window;
-    baseFrameOffset_ = NSZeroPoint;
-  }
-  return self;
-}
-- (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset {
-  baseFrameOffset_ = baseFrameOffset;
-}
-- (NSRect)statusBubbleBaseFrame {
-  NSView* contentView = [window_ contentView];
-  NSRect baseFrame = [contentView convertRect:[contentView frame] toView:nil];
-  if (baseFrameOffset_.x > 0 || baseFrameOffset_.y > 0) {
-    baseFrame = NSOffsetRect(baseFrame, baseFrameOffset_.x, baseFrameOffset_.y);
-    baseFrame.size.width -= baseFrameOffset_.x;
-    baseFrame.size.height -= baseFrameOffset_.y;
-  }
-  return baseFrame;
-}
-- (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state {
-  states_.push_back(state);
-}
-- (std::vector<StatusBubbleMac::StatusBubbleState>*)states {
-  return &states_;
-}
-@end
-
-// This class implements, for testing purposes, a subclass of |StatusBubbleMac|
-// whose |MouseMoved()| method does nothing. This lets the tests fake the mouse
-// position and avoid being affected by the true mouse position.
-class StatusBubbleMacIgnoreMouseMoved : public StatusBubbleMac {
- public:
-  StatusBubbleMacIgnoreMouseMoved(NSWindow* parent, id delegate)
-      : StatusBubbleMac(parent, delegate), mouseLocation_(0, 0) {
-    // Set the fake mouse position to the top right of the content area.
-    NSRect contentBounds = [[parent contentView] bounds];
-    mouseLocation_.SetPoint(NSMaxX(contentBounds), NSMaxY(contentBounds));
-  }
-
-  void MouseMoved(bool left_content) override {}
-
-  gfx::Point GetMouseLocation() override { return mouseLocation_; }
-
-  void SetMouseLocationForTesting(int x, int y) {
-    mouseLocation_.SetPoint(x, y);
-    StatusBubbleMac::MouseMovedAt(gfx::Point(x, y), false);
-  }
-
- private:
-  gfx::Point mouseLocation_;
-};
-
-class StatusBubbleMacTest : public CocoaTest {
- public:
-  void SetUp() override {
-    CocoaTest::SetUp();
-    CocoaTestHelperWindow* window = test_window();
-    EXPECT_TRUE(window);
-    delegate_.reset(
-        [[StatusBubbleMacTestDelegate alloc] initWithWindow: window]);
-    EXPECT_TRUE(delegate_.get());
-    bubble_ = new StatusBubbleMacIgnoreMouseMoved(window, delegate_);
-    EXPECT_TRUE(bubble_);
-
-    // Turn off delays and transitions for test mode.  This doesn't just speed
-    // things along, it's actually required to get StatusBubbleMac to behave
-    // synchronously, because the tests here don't know how to wait for
-    // results.  This allows these tests to be much more complete with a
-    // minimal loss of coverage and without any heinous rearchitecting.
-    bubble_->immediate_ = true;
-
-    EXPECT_TRUE(bubble_->window_);  // immediately creates window
-  }
-
-  void TearDown() override {
-    // Not using a scoped_ptr because bubble must be deleted before calling
-    // TearDown to get rid of bubble's window.
-    delete bubble_;
-    CocoaTest::TearDown();
-  }
-
-  bool IsVisible() {
-    if (![bubble_->window_ isVisible])
-      return false;
-    return [bubble_->window_ alphaValue] > 0.0;
-  }
-  NSString* GetText() {
-    return bubble_->status_text_;
-  }
-  NSString* GetURLText() {
-    return bubble_->url_text_;
-  }
-  NSString* GetBubbleViewText() {
-    BubbleView* bubbleView = [bubble_->window_ contentView];
-    return [bubbleView content];
-  }
-  NSWindow* GetWindow() { return bubble_->GetWindow(); }
-  NSWindow* parent() {
-    return bubble_->parent_;
-  }
-  StatusBubbleMac::StatusBubbleState GetState() {
-    return bubble_->state_;
-  }
-  void SetState(StatusBubbleMac::StatusBubbleState state) {
-    bubble_->SetState(state);
-  }
-  std::vector<StatusBubbleMac::StatusBubbleState>* States() {
-    return [delegate_ states];
-  }
-  StatusBubbleMac::StatusBubbleState StateAt(int index) {
-    return (*States())[index];
-  }
-
-  bool IsPointInBubble(int x, int y) {
-    return NSPointInRect(NSMakePoint(x, y), [GetWindow() frame]);
-  }
-
-  void SetMouseLocation(int relative_x, int relative_y) {
-    // Convert to screen coordinates.
-    NSRect window_frame = [test_window() frame];
-    int x = relative_x + window_frame.origin.x;
-    int y = relative_y + window_frame.origin.y;
-
-    ((StatusBubbleMacIgnoreMouseMoved*)
-      bubble_)->SetMouseLocationForTesting(x, y);
-  }
-
-  // Test helper for moving the fake mouse location, and checking that
-  // the bubble avoids that location.
-  // For convenience & clarity, coordinates are relative to the main window.
-  bool CheckAvoidsMouse(int relative_x, int relative_y) {
-    SetMouseLocation(relative_x, relative_y);
-    return !IsPointInBubble(relative_x, relative_y);
-  }
-
-  base::MessageLoop message_loop_;
-  base::scoped_nsobject<StatusBubbleMacTestDelegate> delegate_;
-  StatusBubbleMac* bubble_;  // Strong.
-};
-
-TEST_F(StatusBubbleMacTest, SetStatus) {
-  bubble_->SetStatus(base::string16());
-  bubble_->SetStatus(UTF8ToUTF16("This is a test"));
-  EXPECT_NSEQ(@"This is a test", GetText());
-  EXPECT_TRUE(IsVisible());
-
-  // Set the status to the exact same thing again
-  bubble_->SetStatus(UTF8ToUTF16("This is a test"));
-  EXPECT_NSEQ(@"This is a test", GetText());
-
-  // Hide it
-  bubble_->SetStatus(base::string16());
-  EXPECT_FALSE(IsVisible());
-}
-
-TEST_F(StatusBubbleMacTest, SetURL) {
-  bubble_->SetURL(GURL());
-  EXPECT_FALSE(IsVisible());
-  bubble_->SetURL(GURL("bad url"));
-  EXPECT_FALSE(IsVisible());
-  bubble_->SetURL(GURL("http://"));
-  EXPECT_FALSE(IsVisible());
-  bubble_->SetURL(GURL("about:blank"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"about:blank", GetURLText());
-  bubble_->SetURL(GURL("foopy://"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"foopy://", GetURLText());
-  bubble_->SetURL(GURL("http://www.cnn.com"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"www.cnn.com", GetURLText());
-}
-
-// Test hiding bubble that's already hidden.
-TEST_F(StatusBubbleMacTest, Hides) {
-  bubble_->SetStatus(UTF8ToUTF16("Showing"));
-  EXPECT_TRUE(IsVisible());
-  bubble_->Hide();
-  EXPECT_FALSE(IsVisible());
-  bubble_->Hide();
-  EXPECT_FALSE(IsVisible());
-}
-
-// Test the "main"/"backup" behavior in StatusBubbleMac::SetText().
-TEST_F(StatusBubbleMacTest, SetStatusAndURL) {
-  EXPECT_FALSE(IsVisible());
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"Status", GetBubbleViewText());
-  bubble_->SetURL(GURL("http://www.nytimes.com"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
-  bubble_->SetURL(GURL());
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"Status", GetBubbleViewText());
-  bubble_->SetStatus(base::string16());
-  EXPECT_FALSE(IsVisible());
-  bubble_->SetURL(GURL("http://www.nytimes.com"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"Status", GetBubbleViewText());
-  bubble_->SetStatus(base::string16());
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
-  bubble_->SetURL(GURL());
-  EXPECT_FALSE(IsVisible());
-}
-
-// Test that the status bubble goes through the correct delay and fade states.
-// The delay and fade duration are simulated and not actually experienced
-// during the test because StatusBubbleMacTest sets immediate_ mode.
-TEST_F(StatusBubbleMacTest, StateTransitions) {
-  // First, some sanity
-
-  EXPECT_FALSE(IsVisible());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-
-  bubble_->SetStatus(base::string16());
-  EXPECT_FALSE(IsVisible());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_TRUE(States()->empty());  // no change from initial kBubbleHidden state
-
-  // Next, a few ordinary cases
-
-  // Test StartShowing from kBubbleHidden
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  EXPECT_TRUE(IsVisible());
-  // Check GetState before checking States to make sure that all state
-  // transitions have been flushed to States.
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
-  EXPECT_EQ(3u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleShowingTimer, StateAt(0));
-  EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(1));
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(2));
-
-  // Test StartShowing from kBubbleShown with the same message
-  States()->clear();
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
-  EXPECT_TRUE(States()->empty());
-
-  // Test StartShowing from kBubbleShown with a different message
-  bubble_->SetStatus(UTF8ToUTF16("New Status"));
-  EXPECT_TRUE(IsVisible());
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
-  EXPECT_TRUE(States()->empty());
-
-  // Test StartHiding from kBubbleShown
-  bubble_->SetStatus(base::string16());
-  EXPECT_FALSE(IsVisible());
-  // Check GetState before checking States to make sure that all state
-  // transitions have been flushed to States.
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_EQ(3u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidingTimer, StateAt(0));
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(1));
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(2));
-
-  // Test StartHiding from kBubbleHidden
-  States()->clear();
-  bubble_->SetStatus(base::string16());
-  EXPECT_FALSE(IsVisible());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_TRUE(States()->empty());
-
-  // Now, the edge cases
-
-  // Test StartShowing from kBubbleShowingTimer
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  SetState(StatusBubbleMac::kBubbleShowingTimer);
-  [GetWindow() setAlphaValue:0.0];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
-  EXPECT_EQ(2u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0));
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1));
-
-  // Test StartShowing from kBubbleShowingFadeIn
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  SetState(StatusBubbleMac::kBubbleShowingFadeIn);
-  [GetWindow() setAlphaValue:0.5];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  // The actual state values can't be tested in immediate_ mode because
-  // the window wasn't actually fading in.  Without immediate_ mode,
-  // expect kBubbleShown.
-  bubble_->SetStatus(base::string16());  // Go back to a deterministic state.
-
-  // Test StartShowing from kBubbleHidingTimer
-  bubble_->SetStatus(base::string16());
-  SetState(StatusBubbleMac::kBubbleHidingTimer);
-  [GetWindow() setAlphaValue:1.0];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
-  EXPECT_EQ(1u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(0));
-
-  // Test StartShowing from kBubbleHidingFadeOut
-  bubble_->SetStatus(base::string16());
-  SetState(StatusBubbleMac::kBubbleHidingFadeOut);
-  [GetWindow() setAlphaValue:0.5];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
-  EXPECT_EQ(2u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0));
-  EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1));
-
-  // Test StartHiding from kBubbleShowingTimer
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  SetState(StatusBubbleMac::kBubbleShowingTimer);
-  [GetWindow() setAlphaValue:0.0];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->SetStatus(base::string16());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_EQ(1u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-
-  // Test StartHiding from kBubbleShowingFadeIn
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  SetState(StatusBubbleMac::kBubbleShowingFadeIn);
-  [GetWindow() setAlphaValue:0.5];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->SetStatus(base::string16());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_EQ(2u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0));
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1));
-
-  // Test StartHiding from kBubbleHidingTimer
-  bubble_->SetStatus(base::string16());
-  SetState(StatusBubbleMac::kBubbleHidingTimer);
-  [GetWindow() setAlphaValue:1.0];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->SetStatus(base::string16());
-  // The actual state values can't be tested in immediate_ mode because
-  // the timer wasn't actually running.  Without immediate_ mode, expect
-  // kBubbleHidingFadeOut and kBubbleHidden.
-  // Go back to a deterministic state.
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-
-  // Test StartHiding from kBubbleHidingFadeOut
-  bubble_->SetStatus(base::string16());
-  SetState(StatusBubbleMac::kBubbleHidingFadeOut);
-  [GetWindow() setAlphaValue:0.5];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->SetStatus(base::string16());
-  // The actual state values can't be tested in immediate_ mode because
-  // the window wasn't actually fading out.  Without immediate_ mode, expect
-  // kBubbleHidden.
-  // Go back to a deterministic state.
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-
-  // Test Hide from kBubbleHidden
-  bubble_->SetStatus(base::string16());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->Hide();
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_TRUE(States()->empty());
-
-  // Test Hide from kBubbleShowingTimer
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  SetState(StatusBubbleMac::kBubbleShowingTimer);
-  [GetWindow() setAlphaValue:0.0];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->Hide();
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_EQ(1u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-
-  // Test Hide from kBubbleShowingFadeIn
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  SetState(StatusBubbleMac::kBubbleShowingFadeIn);
-  [GetWindow() setAlphaValue:0.5];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->Hide();
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_EQ(2u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0));
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1));
-
-  // Test Hide from kBubbleShown
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->Hide();
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_EQ(1u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-
-  // Test Hide from kBubbleHidingTimer
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  SetState(StatusBubbleMac::kBubbleHidingTimer);
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->Hide();
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_EQ(1u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-
-  // Test Hide from kBubbleHidingFadeOut
-  bubble_->SetStatus(UTF8ToUTF16("Status"));
-  SetState(StatusBubbleMac::kBubbleHidingFadeOut);
-  [GetWindow() setAlphaValue:0.5];
-  States()->clear();
-  EXPECT_TRUE(States()->empty());
-  bubble_->Hide();
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
-  EXPECT_EQ(1u, States()->size());
-  EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
-}
-
-TEST_F(StatusBubbleMacTest, Delete) {
-  NSWindow* window = test_window();
-  // Create and delete immediately.
-  StatusBubbleMac* bubble = new StatusBubbleMac(window, nil);
-  delete bubble;
-
-  // Create then delete while visible.
-  bubble = new StatusBubbleMac(window, nil);
-  bubble->SetStatus(UTF8ToUTF16("showing"));
-  delete bubble;
-}
-
-TEST_F(StatusBubbleMacTest, UpdateSizeAndPosition) {
-  // Test |UpdateSizeAndPosition()| when status bubble does not exist (shouldn't
-  // crash; shouldn't create window).
-  EXPECT_TRUE(GetWindow());
-  bubble_->UpdateSizeAndPosition();
-  EXPECT_TRUE(GetWindow());
-
-  // Create a status bubble (with contents) and call resize (without actually
-  // resizing); the frame size shouldn't change.
-  bubble_->SetStatus(UTF8ToUTF16("UpdateSizeAndPosition test"));
-  ASSERT_TRUE(GetWindow());
-  NSRect rect_before = [GetWindow() frame];
-  bubble_->UpdateSizeAndPosition();
-  NSRect rect_after = [GetWindow() frame];
-  EXPECT_NSEQ(rect_before, rect_after);
-
-  // Move the window and call resize; only the origin should change.
-  NSWindow* window = test_window();
-  ASSERT_TRUE(window);
-  NSRect frame = [window frame];
-  rect_before = [GetWindow() frame];
-  frame.origin.x += 10.0;  // (fairly arbitrary nonzero value)
-  frame.origin.y += 10.0;  // (fairly arbitrary nonzero value)
-  [window setFrame:frame display:YES];
-  bubble_->UpdateSizeAndPosition();
-  rect_after = [GetWindow() frame];
-  EXPECT_NE(rect_before.origin.x, rect_after.origin.x);
-  EXPECT_NE(rect_before.origin.y, rect_after.origin.y);
-  EXPECT_EQ(rect_before.size.width, rect_after.size.width);
-  EXPECT_EQ(rect_before.size.height, rect_after.size.height);
-
-  // Resize the window (without moving). The origin shouldn't change. The width
-  // should change (in the current implementation), but not the height.
-  frame = [window frame];
-  rect_before = [GetWindow() frame];
-  frame.size.width += 50.0;   // (fairly arbitrary nonzero value)
-  frame.size.height += 50.0;  // (fairly arbitrary nonzero value)
-  [window setFrame:frame display:YES];
-  bubble_->UpdateSizeAndPosition();
-  rect_after = [GetWindow() frame];
-  EXPECT_EQ(rect_before.origin.x, rect_after.origin.x);
-  EXPECT_EQ(rect_before.origin.y, rect_after.origin.y);
-  EXPECT_NE(rect_before.size.width, rect_after.size.width);
-  EXPECT_EQ(rect_before.size.height, rect_after.size.height);
-}
-
-TEST_F(StatusBubbleMacTest, MovingWindowUpdatesPosition) {
-  NSWindow* window = test_window();
-
-  // Show the bubble and make sure it has the same origin as |window|.
-  bubble_->SetStatus(UTF8ToUTF16("Showing"));
-  NSWindow* child = GetWindow();
-  EXPECT_NSEQ([window frame].origin, [child frame].origin);
-
-  // Hide the bubble, move the window, and show it again.
-  bubble_->Hide();
-  NSRect frame = [window frame];
-  frame.origin.x += 50;
-  [window setFrame:frame display:YES];
-  bubble_->SetStatus(UTF8ToUTF16("Reshowing"));
-
-  // The bubble should reattach in the correct location.
-  child = GetWindow();
-  EXPECT_NSEQ([window frame].origin, [child frame].origin);
-}
-
-TEST_F(StatusBubbleMacTest, StatuBubbleRespectsBaseFrameLimits) {
-  NSWindow* window = test_window();
-
-  // Show the bubble and make sure it has the same origin as |window|.
-  bubble_->SetStatus(UTF8ToUTF16("Showing"));
-  NSWindow* child = GetWindow();
-  EXPECT_NSEQ([window frame].origin, [child frame].origin);
-
-  // Hide the bubble, change base frame offset, and show it again.
-  bubble_->Hide();
-
-  NSPoint baseFrameOffset = NSMakePoint(0, [window frame].size.height / 3);
-  EXPECT_GT(baseFrameOffset.y, 0);
-  [delegate_ forceBaseFrameOffset:baseFrameOffset];
-
-  bubble_->SetStatus(UTF8ToUTF16("Reshowing"));
-
-  // The bubble should reattach in the correct location.
-  child = GetWindow();
-  NSPoint expectedOrigin = [window frame].origin;
-  expectedOrigin.x += baseFrameOffset.x;
-  expectedOrigin.y += baseFrameOffset.y;
-  EXPECT_NSEQ(expectedOrigin, [child frame].origin);
-}
-
-TEST_F(StatusBubbleMacTest, ExpandBubble) {
-  NSWindow* window = test_window();
-
-  // The system font changes between OSX 10.9 and OSX 10.10. Use the system
-  // font from OSX 10.9 for this test.
-  id mockContentView =
-      [OCMockObject partialMockForObject:[GetWindow() contentView]];
-  [[[mockContentView stub]
-      andReturn:[NSFont fontWithName:@"Lucida Grande" size:11]] font];
-
-  ASSERT_TRUE(window);
-  NSRect window_frame = [window frame];
-  window_frame.size.width = 600.0;
-  [window setFrame:window_frame display:YES];
-
-  // Check basic expansion
-  bubble_->SetStatus(UTF8ToUTF16("Showing"));
-  EXPECT_TRUE(IsVisible());
-  bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html"));
-  EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
-  bubble_->ExpandBubble();
-  EXPECT_TRUE(IsVisible());
-  EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText());
-  bubble_->Hide();
-
-  // Make sure bubble resets after hide.
-  bubble_->SetStatus(UTF8ToUTF16("Showing"));
-  bubble_->SetURL(GURL("http://www.snickersnee.com/pioneer_fishstix.html"));
-  EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
-  // ...and that it expands again properly.
-  bubble_->ExpandBubble();
-  EXPECT_NSEQ(@"www.snickersnee.com/pioneer_fishstix.html", GetURLText());
-  // ...again, again!
-  bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html"));
-  bubble_->ExpandBubble();
-  EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText());
-  bubble_->Hide();
-
-  window_frame = [window frame];
-  window_frame.size.width = 300.0;
-  [window setFrame:window_frame display:YES];
-
-  // Very long URL's will be cut off even in the expanded state.
-  bubble_->SetStatus(UTF8ToUTF16("Showing"));
-  const char veryLongUrl[] =
-      "http://www.diewahrscheinlichlaengstepralinederwelt.com/duuuuplo.html";
-  bubble_->SetURL(GURL(veryLongUrl));
-  EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
-  bubble_->ExpandBubble();
-  EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
-}
-
-TEST_F(StatusBubbleMacTest, BubbleAvoidsMouse) {
-  NSWindow* window = test_window();
-
-  // All coordinates here are relative to the window origin.
-
-  // Initially, the bubble should appear in the bottom left.
-  bubble_->SetStatus(UTF8ToUTF16("Showing"));
-  EXPECT_TRUE(IsPointInBubble(0, 0));
-  bubble_->Hide();
-
-  // Check that the bubble doesn't appear in the left corner if the
-  // mouse is currently located there.
-  SetMouseLocation(0, 0);
-  bubble_->SetStatus(UTF8ToUTF16("Showing"));
-  EXPECT_FALSE(IsPointInBubble(0, 0));
-
-  // Leave the bubble visible, and try moving the mouse around.
-  int smallValue = NSHeight([GetWindow() frame]) / 2;
-  EXPECT_TRUE(CheckAvoidsMouse(0, 0));
-  EXPECT_TRUE(CheckAvoidsMouse(smallValue, 0));
-  EXPECT_TRUE(CheckAvoidsMouse(0, smallValue));
-  EXPECT_TRUE(CheckAvoidsMouse(smallValue, smallValue));
-
-  // Simulate moving the mouse down from the top of the window.
-  for (int y = NSHeight([window frame]); y >= 0; y -= smallValue) {
-    ASSERT_TRUE(CheckAvoidsMouse(smallValue, y));
-  }
-
-  // Simulate moving the mouse from left to right.
-  int windowWidth = NSWidth([window frame]);
-  for (int x = 0; x < windowWidth; x += smallValue) {
-    ASSERT_TRUE(CheckAvoidsMouse(x, smallValue));
-  }
-
-  // Simulate moving the mouse from right to left.
-  for (int x = windowWidth; x >= 0; x -= smallValue) {
-    ASSERT_TRUE(CheckAvoidsMouse(x, smallValue));
-  }
-}
-
-TEST_F(StatusBubbleMacTest, ReparentBubble) {
-  // The second window is borderless, like the window used in fullscreen mode.
-  base::scoped_nsobject<NSWindow> fullscreenParent(
-      [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
-                                  styleMask:NSBorderlessWindowMask
-                                    backing:NSBackingStoreBuffered
-                                      defer:NO]);
-
-  // Switch parents with the bubble hidden.
-  bubble_->SwitchParentWindow(fullscreenParent);
-
-  // Switch back to the original parent with the bubble showing.
-  bubble_->SetStatus(UTF8ToUTF16("Showing"));
-  bubble_->SwitchParentWindow(test_window());
-}
-
-TEST_F(StatusBubbleMacTest, WaitsUntilVisible) {
-  [test_window() orderOut:nil];
-  bubble_->SetStatus(UTF8ToUTF16("Show soon"));
-  EXPECT_NSEQ(nil, GetWindow().parentWindow);
-
-  [test_window() orderBack:nil];
-  EXPECT_NSNE(nil, GetWindow().parentWindow);
-}
-
-TEST_F(StatusBubbleMacTest, WaitsUntilOnActiveSpace) {
-  test_window().pretendIsOnActiveSpace = NO;
-  bubble_->SetStatus(UTF8ToUTF16("Show soon"));
-  EXPECT_NSEQ(nil, GetWindow().parentWindow);
-
-  test_window().pretendIsOnActiveSpace = YES;
-  EXPECT_NSNE(nil, GetWindow().parentWindow);
-}
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
index 54d44c8..27e38c4 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.h
@@ -16,8 +16,6 @@
 #include "components/prefs/pref_member.h"
 #import "ui/base/cocoa/tracking_area.h"
 
-@class AutocompleteTextField;
-@class AutocompleteTextFieldEditor;
 @class BackForwardMenuController;
 class Browser;
 class CommandUpdater;
@@ -53,7 +51,7 @@
   IBOutlet ReloadButtonCocoa* reloadButton_;
   IBOutlet ToolbarButtonCocoa* homeButton_;
   IBOutlet MenuButton* appMenuButton_;
-  IBOutlet AutocompleteTextField* locationBar_;
+  IBOutlet id locationBar_;
   IBOutlet id browserActionsContainerView_;
 
  @private
@@ -63,8 +61,6 @@
   std::unique_ptr<ToolbarControllerInternal::CommandObserverBridge>
       commandObserver_;
   std::unique_ptr<LocationBarViewMac> locationBarView_;
-  base::scoped_nsobject<AutocompleteTextFieldEditor>
-      autocompleteTextFieldEditor_;
   base::scoped_nsobject<BackForwardMenuController> backMenuController_;
   base::scoped_nsobject<BackForwardMenuController> forwardMenuController_;
 
diff --git a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
index 3b471c3d..bb8a778 100644
--- a/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
+++ b/chrome/browser/ui/cocoa/toolbar/toolbar_controller.mm
@@ -31,8 +31,6 @@
 #include "chrome/browser/ui/cocoa/drag_util.h"
 #import "chrome/browser/ui/cocoa/image_button_cell.h"
 #import "chrome/browser/ui/cocoa/l10n_util.h"
-#import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_editor.h"
-#import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.h"
 #import "chrome/browser/ui/cocoa/menu_button.h"
 #import "chrome/browser/ui/cocoa/toolbar/app_toolbar_button.h"
@@ -88,9 +86,6 @@
 // wide inset.
 const CGFloat kButtonInset = 2;
 
-// The minimum width of the location bar in pixels.
-const CGFloat kMinimumLocationBarWidth = 100.0;
-
 }  // namespace
 
 @interface ToolbarController()
@@ -108,7 +103,6 @@
 // Height of the toolbar in pixels when the bookmark bar is closed.
 - (CGFloat)baseToolbarHeight;
 - (void)toolbarFrameChanged;
-- (void)showLocationBarOnly;
 - (void)maintainMinimumLocationBarWidth;
 - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate;
 - (void)updateAppMenuButtonSeverity:(AppMenuIconController::Severity)severity
@@ -350,22 +344,7 @@
   [self initCommandStatus:commands_];
   [reloadButton_ setCommandUpdater:commands_];
 
-  locationBarView_.reset(new LocationBarViewMac(locationBar_, commands_,
-                                                profile_, browser_));
-  [locationBar_ setFont:[NSFont systemFontOfSize:14]];
-
-  // Add the location bar's accessibility views as direct subviews of the
-  // toolbar. They are logical children of the location bar, but the location
-  // bar's actual Cocoa control is an NSCell, so it cannot have child views.
-  // The |locationBarView_| is responsible for positioning the accessibility
-  // views.
-  std::vector<NSView*> accessibility_views =
-      locationBarView_->GetDecorationAccessibilityViews();
-  for (const auto& view : accessibility_views) {
-    [[self toolbarView] addSubview:view
-                        positioned:NSWindowAbove
-                        relativeTo:locationBar_];
-  }
+  locationBarView_.reset(new LocationBarViewMac(commands_, profile_, browser_));
 
   // Register pref observers for the optional home and page/options buttons
   // and then add them to the toolbar based on those prefs.
@@ -491,17 +470,6 @@
   [[homeButton_ cell]
       accessibilitySetOverrideValue:description
                        forAttribute:NSAccessibilityDescriptionAttribute];
-  description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_LOCATION);
-  [[locationBar_ cell]
-      accessibilitySetOverrideValue:description
-                       forAttribute:NSAccessibilityDescriptionAttribute];
-  // Expose Cmd+L shortcut in help for now.
-  // TODO(aleventhal) Key shortcuts attribute should eventually get
-  // its own field. Follow what WebKit does for aria-keyshortcuts, see
-  // https://bugs.webkit.org/show_bug.cgi?id=159215 (WebKit bug).
-  [[locationBar_ cell]
-      accessibilitySetOverrideValue:@"\u2318L"  // Expose Cmd+L shortcut.
-                       forAttribute:NSAccessibilityHelpAttribute];
   description = l10n_util::GetNSStringWithFixup(IDS_ACCNAME_APP);
   [[appMenuButton_ cell]
       accessibilitySetOverrideValue:description
@@ -550,19 +518,13 @@
 }
 
 - (void)locationBarWasAddedToWindow {
-  // Allow the |locationBarView_| to update itself to match the browser window
-  // theme.
-  locationBarView_->OnAddedToWindow();
 }
 
 - (BOOL)locationBarHasFocus {
-  return [autocompleteTextFieldEditor_ window] != nil;
+  return NO;
 }
 
 - (void)focusLocationBar:(BOOL)selectAll {
-  if (locationBarView_.get()) {
-    locationBarView_->FocusLocation(selectAll ? true : false);
-  }
 }
 
 // Called when the state for a command changes to |enabled|. Update the
@@ -594,16 +556,11 @@
 }
 
 - (void)updateToolbarWithContents:(WebContents*)tab {
-  locationBarView_->Update(tab);
-
-  [locationBar_ updateMouseTracking];
-
   BOOL needReloadMenu = chrome::IsDebuggerAttachedToCurrentTab(browser_);
   [reloadButton_ setMenuEnabled:needReloadMenu];
 }
 
 - (void)resetTabState:(WebContents*)tab {
-  locationBarView_->ResetTabState(tab);
 }
 
 - (void)setStarredState:(BOOL)isStarred {
@@ -613,7 +570,6 @@
 }
 
 - (void)zoomChangedForActiveTab:(BOOL)canShowBubble {
-  locationBarView_->ZoomChangedForActiveTab(canShowBubble);
 }
 
 - (void)setIsLoading:(BOOL)isLoading force:(BOOL)force {
@@ -625,37 +581,13 @@
 
   hasToolbar_ = toolbar;
 
-  // If there's a toolbar, there must be a location bar.
-  DCHECK((toolbar && locBar) || !toolbar);
-  hasLocationBar_ = toolbar ? YES : locBar;
+  hasLocationBar_ = NO;
 
   // Decide whether to hide/show based on whether there's a location bar.
-  [[self view] setHidden:!hasLocationBar_];
-
-  // Make location bar not editable when in a pop-up or an app window.
-  locationBarView_->SetEditable(toolbar);
-
-  // If necessary, resize the location bar and hide the toolbar icons to display
-  // the toolbar with only the location bar inside it.
-  if (!hasToolbar_ && hasLocationBar_)
-    [self showLocationBarOnly];
+  [[self view] setHidden:!toolbar];
 }
 
 - (id)customFieldEditorForObject:(id)obj {
-  if (obj == locationBar_) {
-    // Lazily construct Field editor, Cocoa UI code always runs on the
-    // same thread, so there shoudn't be a race condition here.
-    if (autocompleteTextFieldEditor_.get() == nil) {
-      autocompleteTextFieldEditor_.reset(
-          [[AutocompleteTextFieldEditor alloc] init]);
-    }
-
-    // This needs to be called every time, otherwise notifications
-    // aren't sent correctly.
-    DCHECK(autocompleteTextFieldEditor_.get());
-    [autocompleteTextFieldEditor_.get() setFieldEditor:YES];
-    return autocompleteTextFieldEditor_.get();
-  }
   return nil;
 }
 
@@ -676,19 +608,6 @@
   if (hide == [homeButton_ isHidden])
     return;  // Nothing to do, view state matches pref state.
 
-  // Always shift the text field by the width of the home button minus one pixel
-  // since the frame edges of each button are right on top of each other. When
-  // hiding the button, reverse the direction of the movement (to the left).
-  CGFloat moveX = [homeButton_ frame].size.width;
-  // Ensure proper spacing between the home button and the location bar.
-  moveX += kElementPadding;
-  if (hide)
-    moveX *= -1;  // Reverse the direction of the move.
-  CGRect locationBarFrame = [locationBar_ frame];
-  locationBarFrame.size.width -= moveX;
-  if (!cocoa_l10n_util::ShouldDoExperimentalRTLLayout())
-    locationBarFrame.origin.x += moveX;
-  [locationBar_ setFrame:locationBarFrame];
   [homeButton_ setHidden:hide];
 }
 
@@ -720,66 +639,12 @@
 }
 
 - (void)maintainMinimumLocationBarWidth {
-  CGFloat locationBarWidth = NSWidth([locationBar_ frame]);
-  locationBarAtMinSize_ = locationBarWidth <= kMinimumLocationBarWidth;
-  if (locationBarAtMinSize_) {
-    CGFloat dX = kMinimumLocationBarWidth - locationBarWidth;
-    [self adjustLocationSizeBy:dX animate:NO];
-  }
 }
 
 - (void)toolbarFrameChanged {
 }
 
-// Hide the back, forward, reload, home, and app menu buttons of the toolbar.
-// This allows the location bar to occupy the entire width. There is no way to
-// undo this operation, and once it is called, no other programmatic changes
-// to the toolbar or location bar width should be made. This message is
-// invalid if the toolbar is shown or the location bar is hidden.
-- (void)showLocationBarOnly {
-  // -showLocationBarOnly is only ever called once, shortly after
-  // initialization, so the regular buttons should all be visible.
-  DCHECK(!hasToolbar_ && hasLocationBar_);
-  DCHECK(![backButton_ isHidden]);
-
-  // Ensure the location bar fills the toolbar.
-  NSRect toolbarFrame = [[self view] frame];
-  toolbarFrame.size.height = [ToolbarController locationBarHeight];
-  [[self view] setFrame:toolbarFrame];
-
-  [locationBar_ setFrame:NSMakeRect(0, 0, NSWidth([[self view] frame]),
-                                    [ToolbarController locationBarHeight])];
-
-  [backButton_ setHidden:YES];
-  [forwardButton_ setHidden:YES];
-  [reloadButton_ setHidden:YES];
-  [appMenuButton_ setHidden:YES];
-  [homeButton_ setHidden:YES];
-}
-
 - (void)adjustLocationSizeBy:(CGFloat)dX animate:(BOOL)animate {
-  NSRect locationFrame = [locationBar_ frame];
-
-  CGFloat location_bar_flex = NSWidth(locationFrame) - kMinimumLocationBarWidth;
-
-  [locationBar_ stopAnimation];
-
-  if (dX == 0)
-    return;
-
-  if (dX < 0) {
-    // Clip to the minimum width. Speculative fix for crbug.com/746944.
-    dX = std::max(dX, -location_bar_flex);
-  }
-  // Ensure that the location bar is in its proper place.
-  locationFrame.size.width += dX;
-  if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout())
-    locationFrame.origin.x -= dX;
-
-  if (animate)
-    [locationBar_ animateToFrame:locationFrame];
-  else
-    [locationBar_ setFrame:locationFrame];
 }
 
 - (NSPoint)bookmarkBubblePoint {
@@ -818,8 +683,7 @@
 }
 
 - (BOOL)isLocationBarFocused {
-  OmniboxEditModel* model = locationBarView_->GetOmniboxView()->model();
-  return model->has_focus();
+  return NO;
 }
 
 // (URLDropTargetController protocol)
diff --git a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
index b647ac7..a61ce08 100644
--- a/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
+++ b/chrome/browser/ui/toolbar/recent_tabs_sub_menu_model_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/sessions/chrome_tab_restore_service_client.h"
@@ -21,6 +22,7 @@
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
 #include "chrome/browser/sync/profile_sync_test_util.h"
+#include "chrome/browser/sync/session_sync_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/sync/browser_synced_window_delegates_getter.h"
@@ -35,11 +37,11 @@
 #include "components/sessions/core/persistent_tab_restore_service.h"
 #include "components/sessions/core/serialized_navigation_entry_test_helper.h"
 #include "components/sessions/core/session_types.h"
-#include "components/sync/base/sync_prefs.h"
 #include "components/sync/device_info/local_device_info_provider_mock.h"
-#include "components/sync/driver/sync_client.h"
+#include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/model/fake_sync_change_processor.h"
 #include "components/sync/model/sync_error_factory_mock.h"
+#include "components/sync_sessions/session_sync_service.h"
 #include "components/sync_sessions/sessions_sync_manager.h"
 #include "components/sync_sessions/synced_session.h"
 #include "content/public/browser/browser_thread.h"
@@ -147,7 +149,9 @@
 class RecentTabsSubMenuModelTest
     : public BrowserWithTestWindowTest {
  public:
-  RecentTabsSubMenuModelTest() {}
+  RecentTabsSubMenuModelTest() {
+    override_features_.InitAndDisableFeature(switches::kSyncUSSSessions);
+  }
 
   void SetUp() override {
     // Set up our mock sync service factory before the sync service (and any
@@ -159,10 +163,11 @@
 
     BrowserWithTestWindowTest::SetUp();
 
-    sync_prefs_ = std::make_unique<syncer::SyncPrefs>(profile()->GetPrefs());
-
     mock_sync_service_ = static_cast<browser_sync::ProfileSyncServiceMock*>(
         ProfileSyncServiceFactory::GetForProfile(profile()));
+    manager_ = static_cast<sync_sessions::SessionsSyncManager*>(
+        SessionSyncServiceFactory::GetForProfile(profile())
+            ->GetSyncableService());
 
     // Needed because ProfileSyncService::Initialize() is not exercised.
     mock_sync_service_->SetLocalDeviceInfoProviderForTest(
@@ -177,12 +182,10 @@
     ON_CALL(*mock_sync_service_, RemoveObserver(_))
         .WillByDefault(Invoke(&fake_sync_service_observer_list_,
                               &FakeSyncServiceObserverList::RemoveObserver));
-
-    manager_ = std::make_unique<sync_sessions::SessionsSyncManager>(
-        mock_sync_service_->GetSyncClient()->GetSyncSessionsClient(),
-        sync_prefs_.get(),
-        base::Bind(&FakeSyncServiceObserverList::NotifyForeignSessionUpdated,
-                   base::Unretained(&fake_sync_service_observer_list_)));
+    ON_CALL(*mock_sync_service_, NotifyForeignSessionUpdated())
+        .WillByDefault(
+            Invoke(&fake_sync_service_observer_list_,
+                   &FakeSyncServiceObserverList::NotifyForeignSessionUpdated));
 
     manager_->MergeDataAndStartSyncing(
         syncer::SESSIONS, syncer::SyncDataList(),
@@ -192,12 +195,6 @@
             new syncer::SyncErrorFactoryMock));
   }
 
-  void TearDown() override {
-    manager_.reset();
-    sync_prefs_.reset();
-    BrowserWithTestWindowTest::TearDown();
-  }
-
   void WaitForLoadFromLastSession() { content::RunAllTasksUntilIdle(); }
 
   void DisableSync() {
@@ -242,7 +239,7 @@
   }
 
   void RegisterRecentTabs(RecentTabsBuilderTestHelper* helper) {
-    helper->ExportToSessionsSyncManager(manager_.get());
+    helper->ExportToSessionsSyncManager(manager_);
   }
 
  private:
@@ -252,14 +249,15 @@
         context, BuildMockProfileSyncService);
   }
 
+  base::test::ScopedFeatureList override_features_;
+
   std::unique_ptr<
       base::CallbackList<void(content::BrowserContext*)>::Subscription>
       will_create_browser_context_services_subscription_;
 
-  std::unique_ptr<syncer::SyncPrefs> sync_prefs_;
   FakeSyncServiceObserverList fake_sync_service_observer_list_;
   browser_sync::ProfileSyncServiceMock* mock_sync_service_ = nullptr;
-  std::unique_ptr<sync_sessions::SessionsSyncManager> manager_;
+  sync_sessions::SessionsSyncManager* manager_;
 
   DISALLOW_COPY_AND_ASSIGN(RecentTabsSubMenuModelTest);
 };
diff --git a/chrome/browser/ui/views/download/download_feedback_dialog_view.cc b/chrome/browser/ui/views/download/download_feedback_dialog_view.cc
deleted file mode 100644
index 4af90f2..0000000
--- a/chrome/browser/ui/views/download/download_feedback_dialog_view.cc
+++ /dev/null
@@ -1,177 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/views/download/download_feedback_dialog_view.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/supports_user_data.h"
-#include "chrome/browser/platform_util.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/ui/browser_dialogs.h"
-#include "chrome/common/pref_names.h"
-#include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/constrained_window/constrained_window_views.h"
-#include "components/prefs/pref_service.h"
-#include "components/safe_browsing/common/safe_browsing_prefs.h"
-#include "components/security_interstitials/core/urls.h"
-#include "components/strings/grit/components_strings.h"
-#include "content/public/browser/page_navigator.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/views/controls/link.h"
-#include "ui/views/controls/message_box_view.h"
-#include "ui/views/widget/widget.h"
-
-using content::OpenURLParams;
-
-namespace {
-
-const void* const kDialogStatusKey = &kDialogStatusKey;
-
-class DialogStatusData : public base::SupportsUserData::Data {
- public:
-  DialogStatusData() : currently_shown_(false) {}
-  ~DialogStatusData() override {}
-  bool currently_shown() const { return currently_shown_; }
-  void set_currently_shown(bool shown) { currently_shown_ = shown; }
- private:
-  bool currently_shown_;
-};
-
-}  // namespace
-
-// static
-void DownloadFeedbackDialogView::Show(
-    gfx::NativeWindow parent_window,
-    Profile* profile,
-    content::PageNavigator* navigator,
-    const UserDecisionCallback& callback) {
-  // This dialog should only be shown if it hasn't been shown before.
-  DCHECK(!safe_browsing::ExtendedReportingPrefExists(*profile->GetPrefs()));
-
-  // Determine if any prefs need to be updated prior to showing the dialog.
-  safe_browsing::UpdatePrefsBeforeSecurityInterstitial(profile->GetPrefs());
-
-  // Only one dialog should be shown at a time, so check to see if another one
-  // is open. If another one is open, treat this parallel call as if reporting
-  // is disabled (to be conservative).
-  DialogStatusData* data =
-      static_cast<DialogStatusData*>(profile->GetUserData(kDialogStatusKey));
-  if (data == NULL) {
-    data = new DialogStatusData();
-    profile->SetUserData(kDialogStatusKey, base::WrapUnique(data));
-  }
-  if (data->currently_shown() == false) {
-    data->set_currently_shown(true);
-    DownloadFeedbackDialogView* window =
-        new DownloadFeedbackDialogView(profile, navigator, callback);
-    constrained_window::CreateBrowserModalDialogViews(
-        window, parent_window)->Show();
-  } else {
-    callback.Run(false);
-  }
-}
-
-DownloadFeedbackDialogView::DownloadFeedbackDialogView(
-    Profile* profile,
-    content::PageNavigator* navigator,
-    const UserDecisionCallback& callback)
-    : profile_(profile),
-      navigator_(navigator),
-      callback_(callback),
-      explanation_box_view_(
-          new views::MessageBoxView(views::MessageBoxView::InitParams(
-              l10n_util::GetStringUTF16(safe_browsing::ChooseOptInTextResource(
-                  *profile->GetPrefs(),
-                  IDS_FEEDBACK_SERVICE_DIALOG_EXPLANATION,
-                  IDS_FEEDBACK_SERVICE_DIALOG_EXPLANATION_SCOUT))))),
-      link_view_(new views::Link(
-          l10n_util::GetStringUTF16(IDS_SAFE_BROWSING_PRIVACY_POLICY_PAGE))),
-      title_text_(l10n_util::GetStringUTF16(IDS_FEEDBACK_SERVICE_DIALOG_TITLE)),
-      ok_button_text_(l10n_util::GetStringUTF16(
-          IDS_FEEDBACK_SERVICE_DIALOG_OK_BUTTON_LABEL)),
-      cancel_button_text_(l10n_util::GetStringUTF16(
-          IDS_FEEDBACK_SERVICE_DIALOG_CANCEL_BUTTON_LABEL)) {
-  link_view_->set_listener(this);
-  chrome::RecordDialogCreation(
-      chrome::DialogIdentifier::SAFE_BROWSING_DOWNLOAD_FEEDBACK);
-}
-
-DownloadFeedbackDialogView::~DownloadFeedbackDialogView() {}
-
-int DownloadFeedbackDialogView::GetDefaultDialogButton() const {
-  return ui::DIALOG_BUTTON_CANCEL;
-}
-
-base::string16 DownloadFeedbackDialogView::GetDialogButtonLabel(
-    ui::DialogButton button) const {
-  return (button == ui::DIALOG_BUTTON_OK) ?
-      ok_button_text_ : cancel_button_text_;
-}
-
-bool DownloadFeedbackDialogView::OnButtonClicked(bool accepted) {
-  safe_browsing::SetExtendedReportingPrefAndMetric(
-      profile_->GetPrefs(), accepted,
-      safe_browsing::SBER_OPTIN_SITE_DOWNLOAD_FEEDBACK_POPUP);
-  DialogStatusData* data =
-     static_cast<DialogStatusData*>(profile_->GetUserData(kDialogStatusKey));
-  DCHECK(data);
-  data->set_currently_shown(false);
-
-  UMA_HISTOGRAM_BOOLEAN("Download.FeedbackDialogEnabled", accepted);
-
-  callback_.Run(accepted);
-  return true;
-}
-
-bool DownloadFeedbackDialogView::Cancel() {
-  return OnButtonClicked(false);
-}
-
-bool DownloadFeedbackDialogView::Accept() {
-  return OnButtonClicked(true);
-}
-
-ui::ModalType DownloadFeedbackDialogView::GetModalType() const {
-  return ui::MODAL_TYPE_WINDOW;
-}
-
-base::string16 DownloadFeedbackDialogView::GetWindowTitle() const {
-  return title_text_;
-}
-
-void DownloadFeedbackDialogView::DeleteDelegate() {
-  delete this;
-}
-
-views::Widget* DownloadFeedbackDialogView::GetWidget() {
-  return explanation_box_view_->GetWidget();
-}
-
-const views::Widget* DownloadFeedbackDialogView::GetWidget() const {
-  return explanation_box_view_->GetWidget();
-}
-
-views::View* DownloadFeedbackDialogView::GetContentsView() {
-  return explanation_box_view_;
-}
-
-views::View* DownloadFeedbackDialogView::CreateExtraView() {
-  return link_view_;
-}
-
-void DownloadFeedbackDialogView::LinkClicked(
-    views::Link* source, int event_flags) {
-  WindowOpenDisposition disposition =
-      ui::DispositionFromEventFlags(event_flags);
-  content::OpenURLParams params(
-      GURL(security_interstitials::kSafeBrowsingPrivacyPolicyUrl),
-      content::Referrer(),
-      disposition == WindowOpenDisposition::CURRENT_TAB
-          ? WindowOpenDisposition::NEW_FOREGROUND_TAB
-          : disposition,
-      ui::PAGE_TRANSITION_LINK, false);
-  navigator_->OpenURL(params);
-}
diff --git a/chrome/browser/ui/views/download/download_feedback_dialog_view.h b/chrome/browser/ui/views/download/download_feedback_dialog_view.h
deleted file mode 100644
index c32ae95..0000000
--- a/chrome/browser/ui/views/download/download_feedback_dialog_view.h
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_VIEWS_DOWNLOAD_DOWNLOAD_FEEDBACK_DIALOG_VIEW_H_
-#define CHROME_BROWSER_UI_VIEWS_DOWNLOAD_DOWNLOAD_FEEDBACK_DIALOG_VIEW_H_
-
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "ui/views/controls/link_listener.h"
-#include "ui/views/window/dialog_delegate.h"
-
-namespace views {
-class MessageBoxView;
-}
-
-namespace content {
-class PageNavigator;
-}
-
-class Profile;
-
-// Asks the user whether they want to participate in the Safe Browsing
-// download feedback program. Shown only for downloads marked DANGEROUS_HOST
-// or UNCOMMON_DOWNLOAD. The user should only see this dialog once.
-class DownloadFeedbackDialogView : public views::DialogDelegate,
-                                   public views::LinkListener {
- public:
-  // Callback with the user's decision. |accepted| is true if the user clicked
-  // Accept(). Otherwise, assume the user cancelled.
-  typedef base::Callback<void(bool accepted)> UserDecisionCallback;
-
-  static void Show(
-      gfx::NativeWindow parent_window,
-      Profile* profile,
-      content::PageNavigator* navigator,
-      const UserDecisionCallback& callback);
-
- private:
-  DownloadFeedbackDialogView(
-      Profile* profile,
-      content::PageNavigator* navigator,
-      const UserDecisionCallback& callback);
-  ~DownloadFeedbackDialogView() override;
-
-  // Handles the user's decision.
-  bool OnButtonClicked(bool accepted);
-
-  // views::DialogDelegate:
-  ui::ModalType GetModalType() const override;
-  base::string16 GetWindowTitle() const override;
-  void DeleteDelegate() override;
-  views::Widget* GetWidget() override;
-  const views::Widget* GetWidget() const override;
-  views::View* GetContentsView() override;
-  int GetDefaultDialogButton() const override;
-  base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
-  bool Cancel() override;
-  bool Accept() override;
-  views::View* CreateExtraView() override;
-
-  // views::LinkListener:
-  void LinkClicked(views::Link* source, int event_flags) override;
-
-  Profile* profile_;
-  content::PageNavigator* navigator_;
-  const UserDecisionCallback callback_;
-  views::MessageBoxView* explanation_box_view_;
-  views::Link* link_view_;
-  base::string16 title_text_;
-  base::string16 ok_button_text_;
-  base::string16 cancel_button_text_;
-
-  DISALLOW_COPY_AND_ASSIGN(DownloadFeedbackDialogView);
-};
-
-#endif  // CHROME_BROWSER_UI_VIEWS_DOWNLOAD_DOWNLOAD_FEEDBACK_DIALOG_VIEW_H_
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index 33fd655..e792a2b 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -32,7 +32,6 @@
 #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
 #include "chrome/browser/safe_browsing/safe_browsing_service.h"
 #include "chrome/browser/themes/theme_properties.h"
-#include "chrome/browser/ui/views/download/download_feedback_dialog_view.h"
 #include "chrome/browser/ui/views/download/download_shelf_context_menu_view.h"
 #include "chrome/browser/ui/views/download/download_shelf_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -216,21 +215,8 @@
 
 void DownloadItemView::MaybeSubmitDownloadToFeedbackService(
     DownloadCommands::Command download_command) {
-  PrefService* prefs = shelf_->browser()->profile()->GetPrefs();
   if (model_->ShouldAllowDownloadFeedback() &&
-      !shelf_->browser()->profile()->IsOffTheRecord()) {
-    if (safe_browsing::ExtendedReportingPrefExists(*prefs)) {
-      SubmitDownloadWhenFeedbackServiceEnabled(
-          download_command, safe_browsing::IsExtendedReportingEnabled(*prefs));
-    } else {
-      // Show dialog, because the dialog hasn't been shown before.
-      DownloadFeedbackDialogView::Show(
-          shelf_->get_parent()->GetNativeWindow(), shelf_->browser()->profile(),
-          shelf_->GetNavigator(),
-          base::Bind(
-              &DownloadItemView::SubmitDownloadWhenFeedbackServiceEnabled,
-              weak_ptr_factory_.GetWeakPtr(), download_command));
-    }
+      SubmitDownloadToFeedbackService(download_command)) {
   } else {
     DownloadCommands(model_.get()).ExecuteCommand(download_command);
   }
@@ -771,8 +757,8 @@
     return false;
   // TODO(shaktisahu): Enable feedback service for offline item.
   if (model_->download()) {
-    download_protection_service->feedback_service()->BeginFeedbackForDownload(
-        model_->download(), download_command);
+    return download_protection_service->MaybeBeginFeedbackForDownload(
+        shelf_->browser()->profile(), model_->download(), download_command);
   }
   // WARNING: we are deleted at this point.  Don't access 'this'.
   return true;
@@ -782,16 +768,6 @@
 #endif
 }
 
-void DownloadItemView::SubmitDownloadWhenFeedbackServiceEnabled(
-    DownloadCommands::Command download_command,
-    bool feedback_enabled) {
-  if (feedback_enabled && SubmitDownloadToFeedbackService(download_command))
-    return;
-
-  DownloadCommands(model_.get()).ExecuteCommand(download_command);
-  // WARNING: 'this' is deleted at this point. Don't access 'this'.
-}
-
 void DownloadItemView::LoadIcon() {
   IconManager* im = g_browser_process->icon_manager();
   last_download_item_path_ = model_->GetTargetFilePath();
diff --git a/chrome/browser/ui/views/download/download_started_animation_views.cc b/chrome/browser/ui/views/download/download_started_animation_views.cc
index fc3f8ea..462d3963 100644
--- a/chrome/browser/ui/views/download/download_started_animation_views.cc
+++ b/chrome/browser/ui/views/download/download_started_animation_views.cc
@@ -6,9 +6,7 @@
 
 #include "base/macros.h"
 #include "base/time/time.h"
-#include "build/build_config.h"
 #include "chrome/app/vector_icons/vector_icons.h"
-#include "chrome/browser/ui/views_mode_controller.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/animation/linear_animation.h"
@@ -123,10 +121,6 @@
 
 // static
 void DownloadStartedAnimation::Show(content::WebContents* web_contents) {
-#if defined(OS_MACOSX)
-  if (views_mode_controller::IsViewsBrowserCocoa())
-    return ShowCocoa(web_contents);
-#endif
   // The animation will delete itself when it's finished.
   new DownloadStartedAnimationViews(web_contents);
 }
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 523c4ab5..65881ea 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -119,6 +119,7 @@
 #include "components/omnibox/browser/omnibox_popup_view.h"
 #include "components/omnibox/browser/omnibox_view.h"
 #include "components/prefs/pref_service.h"
+#include "components/safe_browsing/password_protection/metrics_util.h"
 #include "components/sessions/core/tab_restore_service.h"
 #include "components/signin/core/browser/profile_management_switches.h"
 #include "components/translate/core/browser/language_state.h"
@@ -757,6 +758,13 @@
     top_controls_slide_controller_->SetShownRatio(web_contents, ratio);
 }
 
+bool BrowserView::DoBrowserControlsShrinkRendererSize(
+    const content::WebContents* contents) const {
+  return top_controls_slide_controller_ &&
+         top_controls_slide_controller_->DoBrowserControlsShrinkRendererSize(
+             contents);
+}
+
 int BrowserView::GetTopControlsHeight() const {
   if (top_controls_slide_controller_ &&
       top_controls_slide_controller_->IsEnabled()) {
@@ -2078,6 +2086,7 @@
 void BrowserView::OnWindowEndUserBoundsChange() {
   if (!interactive_resize_)
     return;
+  safe_browsing::LogContentsSize(GetContentsSize());
   auto now = base::TimeTicks::Now();
   DCHECK(!interactive_resize_->begin_timestamp.is_null());
   UMA_HISTOGRAM_TIMES("BrowserWindow.Resize.Duration",
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 4246032b..4015fd36 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -299,6 +299,8 @@
   gfx::NativeWindow GetNativeWindow() const override;
   void SetTopControlsShownRatio(content::WebContents* web_contents,
                                 float ratio) override;
+  bool DoBrowserControlsShrinkRendererSize(
+      const content::WebContents* contents) const override;
   int GetTopControlsHeight() const override;
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
   StatusBubble* GetStatusBubble() override;
diff --git a/chrome/browser/ui/views/frame/browser_window_factory.cc b/chrome/browser/ui/views/frame/browser_window_factory.cc
index 98cd0ad..f3a3c00 100644
--- a/chrome/browser/ui/views/frame/browser_window_factory.cc
+++ b/chrome/browser/ui/views/frame/browser_window_factory.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 #include "chrome/browser/ui/views_mode_controller.h"
 #include "chrome/grit/chromium_strings.h"
+#include "components/safe_browsing/password_protection/metrics_util.h"
 #if defined(USE_AURA)
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -40,5 +41,6 @@
   view->GetWidget()->GetNativeWindow()->SetProperty(
       aura::client::kCreatedByUserGesture, user_gesture);
 #endif
+  safe_browsing::LogContentsSize(view->GetContentsSize());
   return view;
 }
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 19ea3312aa..dfa72ed 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller.h
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller.h
@@ -42,6 +42,12 @@
   virtual void OnBrowserFullscreenStateWillChange(
       bool new_fullscreen_state) = 0;
 
+  // Whether or not the renderer's viewport size has been shrunk by the height
+  // of the browser's top controls.
+  // See BrowserWindow::DoBrowserControlsShrinkRendererSize() for more details.
+  virtual bool DoBrowserControlsShrinkRendererSize(
+      const content::WebContents* contents) const = 0;
+
   // Called from the renderer to inform the controller that gesture scrolling
   // changed state.
   virtual void SetTopControlsGestureScrollInProgress(bool in_progress) = 0;
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 516438f..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
@@ -32,6 +32,11 @@
 
 namespace {
 
+bool IsTabletModeEnabled() {
+  return TabletModeClient::Get() &&
+         TabletModeClient::Get()->tablet_mode_enabled();
+}
+
 // Based on the current status of |contents|, returns the browser top controls
 // shown state constraints, which specifies if the top controls are allowed to
 // be only shown, or either shown or hidden.
@@ -42,7 +47,8 @@
     content::WebContents* contents) {
   DCHECK(contents);
 
-  if (contents->IsFullscreen() || contents->IsFocusedElementEditable() ||
+  if (!IsTabletModeEnabled() || contents->IsFullscreen() ||
+      contents->IsFocusedElementEditable() ||
       contents->ShowingInterstitialPage() || contents->IsBeingDestroyed() ||
       contents->IsCrashed()) {
     return content::BROWSER_CONTROLS_STATE_SHOWN;
@@ -155,7 +161,17 @@
   ~TopControlsSlideTabObserver() override = default;
 
   float shown_ratio() const { return shown_ratio_; }
-  void set_shown_ratio(float ratio) { shown_ratio_ = ratio; }
+  bool shrink_renderer_size() const { return shrink_renderer_size_; }
+
+  void SetShownRatio(float ratio, bool sliding_in_progress) {
+    shown_ratio_ = ratio;
+    if (!sliding_in_progress)
+      UpdateDoBrowserControlsShrinkRendererSize();
+  }
+
+  void UpdateDoBrowserControlsShrinkRendererSize() {
+    shrink_renderer_size_ = shown_ratio_ > 0;
+  }
 
   // content::WebContentsObserver:
   void RenderProcessGone(base::TerminationStatus status) override {
@@ -230,6 +246,12 @@
   //   should be shown.
   float shown_ratio_ = 1.f;
 
+  // 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 is in progress.
+  // https://crbug.com/885223.
+  bool shrink_renderer_size_ = true;
+
   DISALLOW_COPY_AND_ASSIGN(TopControlsSlideTabObserver);
 };
 
@@ -238,10 +260,7 @@
 
 TopControlsSlideControllerChromeOS::TopControlsSlideControllerChromeOS(
     BrowserView* browser_view)
-    : browser_view_(browser_view),
-      tablet_mode_enabled_(TabletModeClient::Get() &&
-                           TabletModeClient::Get()->tablet_mode_enabled()),
-      browser_frame_is_fullscreen_(browser_view->IsFullscreen()) {
+    : browser_view_(browser_view) {
   DCHECK(browser_view);
   DCHECK(browser_view->frame());
   DCHECK(browser_view->browser());
@@ -253,17 +272,23 @@
 
   if (TabletModeClient::Get())
     TabletModeClient::Get()->AddObserver(this);
-  browser_view->browser()->tab_strip_model()->AddObserver(this);
+
+  browser_view_->browser()->tab_strip_model()->AddObserver(this);
+
+  OnEnabledStateChanged(IsTabletModeEnabled() && !browser_view->IsFullscreen());
 }
 
 TopControlsSlideControllerChromeOS::~TopControlsSlideControllerChromeOS() {
+  OnEnabledStateChanged(false);
+
   browser_view_->browser()->tab_strip_model()->RemoveObserver(this);
+
   if (TabletModeClient::Get())
     TabletModeClient::Get()->RemoveObserver(this);
 }
 
 bool TopControlsSlideControllerChromeOS::IsEnabled() const {
-  return tablet_mode_enabled_ && !browser_frame_is_fullscreen_;
+  return is_enabled_;
 }
 
 float TopControlsSlideControllerChromeOS::GetShownRatio() const {
@@ -275,35 +300,55 @@
     float ratio) {
   DCHECK(contents);
 
-  if (!IsEnabled())
+  // 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));
+  observed_tabs_[contents]->SetShownRatio(ratio, is_sliding_in_progress_);
+
+  if (!IsEnabled()) {
+    // However, if sliding is disabled, we don't update |shown_ratio_|, which is
+    // the current value for the entire browser, and it must always be 1.f (i.e.
+    // the top controls are fully shown).
+    DCHECK_EQ(shown_ratio_, 1.f);
     return;
+  }
 
   if (shown_ratio_ == ratio)
     return;
 
   shown_ratio_ = ratio;
-  DCHECK(observed_tabs_.count(contents));
-  observed_tabs_[contents]->set_shown_ratio(ratio);
 
   Refresh();
+
+  // When disabling is deferred, we're waiting for the render to fully show top-
+  // chrome, so look for a value of 1.f. The renderer may be animating towards
+  // that value.
+  if (defer_disabling_ && shown_ratio_ == 1.f) {
+    defer_disabling_ = false;
+
+    // Don't just set |is_enabled_| to false. Make sure it's a correct value.
+    OnEnabledStateChanged(IsTabletModeEnabled() &&
+                          !browser_view_->IsFullscreen());
+  }
 }
 
 void TopControlsSlideControllerChromeOS::OnBrowserFullscreenStateWillChange(
     bool new_fullscreen_state) {
-  auto* active_web_contents = browser_view_->GetActiveWebContents();
-  if (new_fullscreen_state && !browser_frame_is_fullscreen_ &&
-      shown_ratio_ < 1.f) {
-    // Immersive fullscreen mode could be about to start for this browser's
-    // window. Therefore show the top-chrome immediately without animation.
-    ShowTopChrome(active_web_contents, false /* animate */);
+  OnEnabledStateChanged(IsTabletModeEnabled() && !new_fullscreen_state);
+}
+
+bool TopControlsSlideControllerChromeOS::DoBrowserControlsShrinkRendererSize(
+    const content::WebContents* contents) const {
+  if (!IsEnabled())
+    return false;
+
+  auto iter = observed_tabs_.find(contents);
+  if (iter == observed_tabs_.end()) {
+    // this may be called for a new tab that hasn't attached yet to the tabstrip
+    return false;
   }
 
-  browser_frame_is_fullscreen_ = new_fullscreen_state;
-
-  // Now that the state of this feature is changed, force the renderer to get
-  // the new top controls height by triggering a visual properties
-  // synchrnoization event.
-  SynchronizeVisualProperties(active_web_contents);
+  return iter->second->shrink_renderer_size();
 }
 
 void TopControlsSlideControllerChromeOS::SetTopControlsGestureScrollInProgress(
@@ -324,17 +369,9 @@
   Refresh();
 }
 
-void TopControlsSlideControllerChromeOS::OnTabletModeToggled(bool enabled) {
-  auto* active_web_contents = browser_view_->GetActiveWebContents();
-  if (!enabled)
-    ShowTopChrome(active_web_contents, false /* animate */);
-
-  tablet_mode_enabled_ = enabled;
-
-  // Now that the state of this feature is changed, force the renderer to get
-  // the new top controls height by triggering a visual properties
-  // synchrnoization event.
-  SynchronizeVisualProperties(active_web_contents);
+void TopControlsSlideControllerChromeOS::OnTabletModeToggled(
+    bool tablet_mode_enabled) {
+  OnEnabledStateChanged(tablet_mode_enabled && !browser_view_->IsFullscreen());
 }
 
 void TopControlsSlideControllerChromeOS::TabInsertedAt(
@@ -389,7 +426,8 @@
 void TopControlsSlideControllerChromeOS::SetTabNeedsAttentionAt(
     int index,
     bool attention) {
-  ShowTopChrome(browser_view_->GetActiveWebContents(), true /* animate */);
+  UpdateBrowserControlsStateShown(browser_view_->GetActiveWebContents(),
+                                  true /* animate */);
 }
 
 void TopControlsSlideControllerChromeOS::Observe(
@@ -401,13 +439,58 @@
   if (type != content::NOTIFICATION_FOCUS_CHANGED_IN_PAGE)
     return;
 
+  // Make sure this notification is meant for us.
+  content::WebContents* active_contents = browser_view_->GetActiveWebContents();
+  content::RenderViewHost* render_view_host =
+      content::Source<content::RenderViewHost>(source).ptr();
+  if (!active_contents || content::WebContents::FromRenderViewHost(
+                              render_view_host) != active_contents) {
+    return;
+  }
+
   content::FocusedNodeDetails* node_details =
       content::Details<content::FocusedNodeDetails>(details).ptr();
   // If a non-editable node gets focused and top-chrome is fully shown, we
   // should also update the browser controls state constraints so that
   // top-chrome is able to be hidden again.
   if (node_details->is_editable_node || shown_ratio_ == 1.f)
-    ShowTopChrome(browser_view_->GetActiveWebContents(), true /* animate */);
+    UpdateBrowserControlsStateShown(active_contents, true /* animate */);
+}
+
+void TopControlsSlideControllerChromeOS::OnEnabledStateChanged(bool new_state) {
+  if (new_state == is_enabled_)
+    return;
+
+  is_enabled_ = new_state;
+
+  TabStripModel* tab_strip_model = browser_view_->browser()->tab_strip_model();
+  content::WebContents* active_contents =
+      tab_strip_model->GetActiveWebContents();
+  if (!active_contents)
+    return;
+
+  if (!new_state && shown_ratio_ < 1.f) {
+    // We should never set the shown ratio immediately here, rather ask the
+    // renderer to show top-chrome without animation. Since this will happen
+    // later asynchronously, we need to defer the enabled status update until
+    // we get called by the renderer to set the shown ratio to 1.f. Otherwise
+    // we will layout the page to a smaller height before the renderer gets
+    // to know that it needs to update the shown ratio to 1.f.
+    // https://crbug.com/884453.
+    is_enabled_ = true;
+    defer_disabling_ = true;
+  } else {
+    defer_disabling_ = false;
+
+    // Now that the state of this feature is changed, force the renderer to get
+    // the new top controls height by triggering a visual properties
+    // synchrnoization event.
+    SynchronizeVisualProperties(active_contents);
+  }
+
+  // This will also update the browser controls state constraints in the render
+  // now that the state changed.
+  UpdateBrowserControlsStateShown(active_contents, false /* animate */);
 }
 
 void TopControlsSlideControllerChromeOS::Refresh() {
@@ -510,6 +593,10 @@
   // It should never be called while gesture scrolling is still in progress.
   DCHECK(!is_gesture_scrolling_in_progress_);
 
+  // If disabling is deferred, sliding should end only when top-chrome is fully
+  // shown.
+  DCHECK(!defer_disabling_ || (shown_ratio_ == 1.f));
+
   // It can, however, be called when sliding is not in progress as a result of
   // Setting the value directly (for example due to renderer crash), or a direct
   // call from the renderer to set the shown ratio to a terminal value.
@@ -543,6 +630,11 @@
   const int original_height = root_bounds.height();
   const int new_height = widget_layer->bounds().height();
 
+  // This must be updated here **before** the browser is laid out, since the
+  // renderer (as a result of the layout) may query this value, and hence it
+  // should be correct.
+  UpdateDoBrowserControlsShrinkRendererSize();
+
   // We need to guarantee a browser view re-layout, but want to avoid doing that
   // twice.
   if (new_height != original_height) {
@@ -561,15 +653,19 @@
   widget_layer->SetMasksToBounds(shown_ratio_ < 1.f);
 }
 
-void TopControlsSlideControllerChromeOS::ShowTopChrome(
-    content::WebContents* contents,
-    bool animate) {
-  // If |animate| is true, we will rely on the renderer's compositor animating
-  // the value of the shown ratio and updating us by calling SetShownRatio()
-  // repeatedly. Otherwise we will set the shown ratio to 1.f immediately.
-  if (!animate)
-    SetShownRatio(contents, 1.f);
+void TopControlsSlideControllerChromeOS::
+    UpdateDoBrowserControlsShrinkRendererSize() {
+  // It should never be called while gesture scrolling is still in progress.
+  DCHECK(!is_gesture_scrolling_in_progress_);
 
-  // We also must synchronize with the renderer.
-  UpdateBrowserControlsStateShown(contents, animate);
+  // Nor should it be called while sliding is in progress.
+  DCHECK(!is_sliding_in_progress_);
+
+  content::WebContents* active_contents = browser_view_->GetActiveWebContents();
+  if (!active_contents)
+    return;
+
+  DCHECK(observed_tabs_.count(active_contents));
+
+  observed_tabs_[active_contents]->UpdateDoBrowserControlsShrinkRendererSize();
 }
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 7fc887c..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
@@ -48,10 +48,12 @@
   float GetShownRatio() const override;
   void SetShownRatio(content::WebContents* contents, float ratio) override;
   void OnBrowserFullscreenStateWillChange(bool new_fullscreen_state) override;
+  bool DoBrowserControlsShrinkRendererSize(
+      const content::WebContents* contents) const override;
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
 
   // TabletModeClientObserver:
-  void OnTabletModeToggled(bool enabled) override;
+  void OnTabletModeToggled(bool tablet_mode_enabled) override;
 
   // TabStripModelObserver:
   // TODO(afakhry): The below overrides are deprecated, but we have to keep
@@ -79,6 +81,8 @@
                const content::NotificationDetails& details) override;
 
  private:
+  void OnEnabledStateChanged(bool new_state);
+
   // Refreshes the status of the browser top controls.
   void Refresh();
 
@@ -94,10 +98,9 @@
   // BrowserView is laid out into its final bounds.
   void OnEndSliding();
 
-  // Shows the top-chrome completely and updates the renderer of |contents| so
-  // that the values of the |shown_ratio_| and the renderer's
-  // |LayerTreeImpl::top_controls_shown_ratio_| are synchronized.
-  void ShowTopChrome(content::WebContents* contents, bool animate);
+  // Updates whether the currently active tab has shrunk its renderer's viewport
+  // size.
+  void UpdateDoBrowserControlsShrinkRendererSize();
 
   BrowserView* browser_view_;
 
@@ -105,13 +108,20 @@
   // controls that is currently applied.
   float shown_ratio_ = 1.f;
 
-  // The following two values are cached here since they need to be queried
-  // whenever we get an update from the renderer to adjust the shown ratio.
-  // These updates result from touch gesture scrolls, so we need to minimize the
-  // work we do to get these values, so sliding the browser top controls feels
-  // smooth.
-  bool tablet_mode_enabled_;
-  bool browser_frame_is_fullscreen_;
+  // Indicates whether sliding the top controls with gesture scrolls is
+  // currently enabled, which is true when tablet mode is enabled and the
+  // browser window is not full-screened. This value is cached here since it
+  // needs to be queried whenever we get an update from the renderer to adjust
+  // the shown ratio. These updates result from touch gesture scrolls, so we
+  // need to minimize the work we do to get these values, so sliding the browser
+  // top controls feels smooth.
+  bool is_enabled_ = false;
+
+  // Whether we need to wait for the renderer to set the shown ratio to 1.f
+  // before we toggle |is_enabled_| to false. It is used to postpone disabling
+  // top-chrome sliding until the renderer responds so that we can make sure
+  // both the renderer and the browser are both synchronized.
+  bool defer_disabling_ = false;
 
   // Indicates whether a touch gesture scrolling is in progress. This value is
   // updated by the renderer when it receives a GestureEventAck of type either
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 bd7d042..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
@@ -250,6 +250,10 @@
 
       // Widget should not allow things to show outside its bounds.
       EXPECT_TRUE(browser_view->frame()->GetLayer()->GetMasksToBounds());
+
+      // The browser controls doesn't shrink the blink viewport size.
+      EXPECT_FALSE(browser_view->DoBrowserControlsShrinkRendererSize(
+          browser_view->GetActiveWebContents()));
     } else {
       // Top container start at the top.
       EXPECT_EQ(top_container_bounds.y(), 0);
@@ -261,6 +265,10 @@
                 browser_view->contents_container()->height());
 
       EXPECT_FALSE(browser_view->frame()->GetLayer()->GetMasksToBounds());
+
+      // The browser controls does shrink the blink viewport size.
+      EXPECT_TRUE(browser_view->DoBrowserControlsShrinkRendererSize(
+          browser_view->GetActiveWebContents()));
     }
   }
 
@@ -297,6 +305,8 @@
 
   // Renderer will get a zero-height top controls.
   EXPECT_EQ(browser_view->GetTopControlsHeight(), 0);
+  EXPECT_FALSE(browser_view->DoBrowserControlsShrinkRendererSize(
+      browser_view->GetActiveWebContents()));
 }
 
 IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest,
@@ -311,6 +321,8 @@
   // The browser reports a zero height for top-chrome UIs when the behavior is
   // disabled, so the render doesn't think it needs to move the top controls.
   EXPECT_EQ(browser_view()->GetTopControlsHeight(), 0);
+  EXPECT_FALSE(browser_view()->DoBrowserControlsShrinkRendererSize(
+      browser_view()->GetActiveWebContents()));
 
   // Now enable tablet mode.
   ToggleTabletMode();
@@ -321,23 +333,31 @@
   EXPECT_TRUE(top_controls_slide_controller()->IsEnabled());
   EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 1.f);
   EXPECT_NE(browser_view()->GetTopControlsHeight(), 0);
+  EXPECT_TRUE(browser_view()->DoBrowserControlsShrinkRendererSize(
+      browser_view()->GetActiveWebContents()));
 
   // Immersive fullscreen mode disables the behavior.
   chrome::ToggleFullscreenMode(browser());
   EXPECT_TRUE(browser_view()->IsFullscreen());
   EXPECT_FALSE(top_controls_slide_controller()->IsEnabled());
   EXPECT_EQ(browser_view()->GetTopControlsHeight(), 0);
+  EXPECT_FALSE(browser_view()->DoBrowserControlsShrinkRendererSize(
+      browser_view()->GetActiveWebContents()));
 
   // Exit immersive mode.
   chrome::ToggleFullscreenMode(browser());
   EXPECT_FALSE(browser_view()->IsFullscreen());
   EXPECT_TRUE(top_controls_slide_controller()->IsEnabled());
   EXPECT_NE(browser_view()->GetTopControlsHeight(), 0);
+  EXPECT_TRUE(browser_view()->DoBrowserControlsShrinkRendererSize(
+      browser_view()->GetActiveWebContents()));
 
   ToggleTabletMode();
   EXPECT_FALSE(GetTabletModeEnabled());
   EXPECT_FALSE(top_controls_slide_controller()->IsEnabled());
   EXPECT_EQ(browser_view()->GetTopControlsHeight(), 0);
+  EXPECT_FALSE(browser_view()->DoBrowserControlsShrinkRendererSize(
+      browser_view()->GetActiveWebContents()));
 }
 
 IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest, TestScrollingPage) {
@@ -431,6 +451,16 @@
   waiter.WaitForRatio(0.f);
   EXPECT_FLOAT_EQ(top_controls_slide_controller()->GetShownRatio(), 0);
   CheckBrowserLayout(browser_view(), TopChromeShownState::kFullyHidden);
+
+  // The `DoBrowserControlsShrinkRendererSize` bit is separately tracked for
+  // each tab.
+  auto* tab_strip_model = browser()->tab_strip_model();
+  auto* scrollable_page_contents = tab_strip_model->GetWebContentsAt(0);
+  auto* ntp_contents = tab_strip_model->GetWebContentsAt(1);
+  EXPECT_TRUE(
+      browser_view()->DoBrowserControlsShrinkRendererSize(ntp_contents));
+  EXPECT_FALSE(browser_view()->DoBrowserControlsShrinkRendererSize(
+      scrollable_page_contents));
 }
 
 IN_PROC_BROWSER_TEST_F(TopControlsSlideControllerTest, TestClosingATab) {
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index c6aac0c..f79a4475 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -203,7 +203,15 @@
   ]
 
   if (use_command_buffer) {
-    sources += [ "skia_surface_provider_factory_cmd_buffer.cc" ]
+    sources += [
+      "cmd_buffer_surface_provider.cc",
+      "cmd_buffer_surface_provider.h",
+      "skia_surface_provider_factory_cmd_buffer.cc",
+    ]
+    deps += [
+      "//gpu/command_buffer/client:gles2_implementation",
+      "//gpu/skia_bindings",
+    ]
   } else {
     sources += [
       "native_gl_surface_provider.cc",
diff --git a/chrome/browser/vr/cmd_buffer_surface_provider.cc b/chrome/browser/vr/cmd_buffer_surface_provider.cc
new file mode 100644
index 0000000..b148eaeb
--- /dev/null
+++ b/chrome/browser/vr/cmd_buffer_surface_provider.cc
@@ -0,0 +1,58 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/vr/cmd_buffer_surface_provider.h"
+
+#include "base/logging.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/gles2_lib.h"
+#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace vr {
+
+CmdBufferSurfaceProvider::CmdBufferSurfaceProvider() {
+  auto* gles2_implementation =
+      static_cast<gpu::gles2::GLES2Implementation*>(gles2::GetGLContext());
+  DCHECK(gles2_implementation);
+  sk_sp<const GrGLInterface> gr_interface =
+      skia_bindings::CreateGLES2InterfaceBindings(gles2_implementation,
+                                                  gles2_implementation);
+  gr_context_ = GrContext::MakeGL(std::move(gr_interface));
+  DCHECK(gr_context_);
+  glGetIntegerv(GL_FRAMEBUFFER_BINDING, &main_fbo_);
+}
+
+CmdBufferSurfaceProvider::~CmdBufferSurfaceProvider() = default;
+
+sk_sp<SkSurface> CmdBufferSurfaceProvider::MakeSurface(const gfx::Size& size) {
+  return SkSurface::MakeRenderTarget(
+      gr_context_.get(), SkBudgeted::kNo,
+      SkImageInfo::MakeN32Premul(size.width(), size.height()), 0,
+      kTopLeft_GrSurfaceOrigin, nullptr);
+}
+
+GLuint CmdBufferSurfaceProvider::FlushSurface(SkSurface* surface,
+                                              GLuint reuse_texture_id) {
+  surface->getCanvas()->flush();
+  GrBackendTexture backend_texture =
+      surface->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess);
+  DCHECK(backend_texture.isValid());
+  GrGLTextureInfo info;
+  bool result = backend_texture.getGLTextureInfo(&info);
+  DCHECK(result);
+  GLuint texture_id = info.fID;
+  DCHECK_NE(texture_id, 0u);
+  surface->getCanvas()->getGrContext()->resetContext();
+  glBindFramebuffer(GL_FRAMEBUFFER, main_fbo_);
+
+  return texture_id;
+}
+
+}  // namespace vr
diff --git a/chrome/browser/vr/cmd_buffer_surface_provider.h b/chrome/browser/vr/cmd_buffer_surface_provider.h
new file mode 100644
index 0000000..a8e72976
--- /dev/null
+++ b/chrome/browser/vr/cmd_buffer_surface_provider.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_VR_CMD_BUFFER_SURFACE_PROVIDER_H_
+#define CHROME_BROWSER_VR_CMD_BUFFER_SURFACE_PROVIDER_H_
+
+#include "chrome/browser/vr/skia_surface_provider.h"
+#include "chrome/browser/vr/vr_ui_export.h"
+
+class GrContext;
+
+namespace vr {
+
+class VR_UI_EXPORT CmdBufferSurfaceProvider : public SkiaSurfaceProvider {
+ public:
+  CmdBufferSurfaceProvider();
+  ~CmdBufferSurfaceProvider() override;
+
+  sk_sp<SkSurface> MakeSurface(const gfx::Size& size) override;
+  GLuint FlushSurface(SkSurface* surface, GLuint reuse_texture_id) override;
+
+ private:
+  sk_sp<GrContext> gr_context_;
+  GLint main_fbo_ = 0;
+};
+
+}  // namespace vr
+
+#endif  // CHROME_BROWSER_VR_CMD_BUFFER_SURFACE_PROVIDER_H_
diff --git a/chrome/browser/vr/skia_surface_provider_factory_cmd_buffer.cc b/chrome/browser/vr/skia_surface_provider_factory_cmd_buffer.cc
index 42702c7..3af44fc 100644
--- a/chrome/browser/vr/skia_surface_provider_factory_cmd_buffer.cc
+++ b/chrome/browser/vr/skia_surface_provider_factory_cmd_buffer.cc
@@ -4,14 +4,12 @@
 
 #include "chrome/browser/vr/skia_surface_provider_factory.h"
 
-#include "base/logging.h"
+#include "chrome/browser/vr/cmd_buffer_surface_provider.h"
 
 namespace vr {
 
 std::unique_ptr<SkiaSurfaceProvider> SkiaSurfaceProviderFactory::Create() {
-  // TODO(crbug/884256): Implement a surface provider using the command buffer.
-  NOTIMPLEMENTED();
-  return nullptr;
+  return std::make_unique<CmdBufferSurfaceProvider>();
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/test/gl_test_environment_unittest.cc b/chrome/browser/vr/test/gl_test_environment_unittest.cc
index 783e727..ee62da2 100644
--- a/chrome/browser/vr/test/gl_test_environment_unittest.cc
+++ b/chrome/browser/vr/test/gl_test_environment_unittest.cc
@@ -10,13 +10,9 @@
 namespace vr {
 
 TEST(GlTestEnvironmentTest, InitializeAndCleanup) {
-// TODO(crbug/771794): Test temporarily disabled on Windows because it crashes
-// on trybots. Fix before enabling Windows support.
-#ifndef OS_WIN
   GlTestEnvironment gl_test_environment(gfx::Size(100, 100));
   EXPECT_NE(gl_test_environment.GetFrameBufferForTesting(), 0u);
   EXPECT_EQ(glGetError(), (GLenum)GL_NO_ERROR);
-#endif
   // We just test that clean up doesn't crash.
 }
 
diff --git a/chrome/browser/vr/test/run_all_perftests.cc b/chrome/browser/vr/test/run_all_perftests.cc
index 9b7663af..cec581f3 100644
--- a/chrome/browser/vr/test/run_all_perftests.cc
+++ b/chrome/browser/vr/test/run_all_perftests.cc
@@ -4,13 +4,13 @@
 
 #include "base/bind.h"
 #include "base/test/launcher/unit_test_launcher.h"
-#include "chrome/browser/vr/test/vr_test_suite.h"
+#include "chrome/browser/vr/test/vr_gl_test_suite.h"
 
 int main(int argc, char** argv) {
-  vr::VrTestSuite test_suite(argc, argv);
+  vr::VrGlTestSuite test_suite(argc, argv);
 
   return base::LaunchUnitTestsSerially(
       argc, argv,
-      base::BindRepeating(&vr::VrTestSuite::Run,
+      base::BindRepeating(&vr::VrGlTestSuite::Run,
                           base::Unretained(&test_suite)));
 }
diff --git a/chrome/browser/vr/test/ui_pixel_test.cc b/chrome/browser/vr/test/ui_pixel_test.cc
index b0b20c9..b5062b3 100644
--- a/chrome/browser/vr/test/ui_pixel_test.cc
+++ b/chrome/browser/vr/test/ui_pixel_test.cc
@@ -21,9 +21,6 @@
 UiPixelTest::~UiPixelTest() = default;
 
 void UiPixelTest::SetUp() {
-// TODO(crbug/771794): Test temporarily disabled on Windows because it crashes
-// on trybots. Fix before enabling Windows support.
-#ifndef OS_WIN
   gl_test_environment_ =
       std::make_unique<GlTestEnvironment>(frame_buffer_size_);
 
@@ -36,17 +33,12 @@
   ASSERT_EQ(glGetError(), (GLenum)GL_NO_ERROR);
 
   browser_ = std::make_unique<MockUiBrowserInterface>();
-#endif
 }
 
 void UiPixelTest::TearDown() {
-// TODO(crbug/771794): Test temporarily disabled on Windows because it crashes
-// on trybots. Fix before enabling Windows support.
-#ifndef OS_WIN
   ui_.reset();
   glDeleteTextures(1, &content_texture_);
   gl_test_environment_.reset();
-#endif
 }
 
 void UiPixelTest::MakeUi(const UiInitialState& ui_initial_state,
diff --git a/chrome/browser/vr/test/vr_gl_test_suite.cc b/chrome/browser/vr/test/vr_gl_test_suite.cc
index e5af480..d47e18d 100644
--- a/chrome/browser/vr/test/vr_gl_test_suite.cc
+++ b/chrome/browser/vr/test/vr_gl_test_suite.cc
@@ -8,10 +8,11 @@
 #include "ui/gl/test/gl_image_test_support.h"
 
 #if defined(VR_USE_COMMAND_BUFFER)
-#include "gpu/config/gpu_info_collector.h"      // nogncheck
-#include "gpu/config/gpu_preferences.h"         // nogncheck
-#include "gpu/config/gpu_util.h"                // nogncheck
-#include "gpu/ipc/in_process_command_buffer.h"  // nogncheck
+#include "gpu/command_buffer/client/gles2_lib.h"  // nogncheck
+#include "gpu/config/gpu_info_collector.h"        // nogncheck
+#include "gpu/config/gpu_preferences.h"           // nogncheck
+#include "gpu/config/gpu_util.h"                  // nogncheck
+#include "gpu/ipc/in_process_command_buffer.h"    // nogncheck
 #endif  // defined(VR_USE_COMMAND_BUFFER)
 
 namespace vr {
@@ -36,6 +37,7 @@
       gpu::kGpuFeatureStatusEnabled;
   gpu::InProcessCommandBuffer::InitializeDefaultServiceForTesting(
       gpu_feature_info);
+  gles2::Initialize();
 #endif  // defined(VR_USE_COMMAND_BUFFER)
 }
 
diff --git a/chrome/browser/vr/text_perftest.cc b/chrome/browser/vr/text_perftest.cc
index 3fa2b15..172d674 100644
--- a/chrome/browser/vr/text_perftest.cc
+++ b/chrome/browser/vr/text_perftest.cc
@@ -36,6 +36,7 @@
 
   void TearDown() override {
     text_element_.reset();
+    provider_.reset();
     gl_test_environment_.reset();
   }
 
@@ -59,8 +60,8 @@
   cc::LapTimer timer_;
 
  private:
-  std::unique_ptr<GlTestEnvironment> gl_test_environment_;
   std::unique_ptr<SkiaSurfaceProvider> provider_;
+  std::unique_ptr<GlTestEnvironment> gl_test_environment_;
 };
 
 TEST_F(TextPerfTest, RenderLoremIpsum100Chars) {
diff --git a/chrome/browser/vr/ui_pixeltest.cc b/chrome/browser/vr/ui_pixeltest.cc
index 2d29e12..64c15d3 100644
--- a/chrome/browser/vr/ui_pixeltest.cc
+++ b/chrome/browser/vr/ui_pixeltest.cc
@@ -14,19 +14,11 @@
 
 namespace {
 
-static const gfx::Transform kIdentity;
+constexpr gfx::Transform kIdentity;
 
 }  // namespace
 
-// TODO(crbug/771794): Test temporarily disabled on Windows because it crashes
-// on trybots. Fix before enabling Windows support.
-#if defined(OS_WIN)
-#define MAYBE(x) DISABLED_##x
-#else
-#define MAYBE(x) x
-#endif
-
-TEST_F(UiPixelTest, MAYBE(DrawVrBrowsingMode)) {
+TEST_F(UiPixelTest, DrawVrBrowsingMode) {
   // Set up scene.
   UiInitialState ui_initial_state;
   ui_initial_state.in_web_vr = false;
diff --git a/chrome/notification_helper/OWNERS b/chrome/notification_helper/OWNERS
index a537112..ae9c4f8 100644
--- a/chrome/notification_helper/OWNERS
+++ b/chrome/notification_helper/OWNERS
@@ -1,3 +1,4 @@
 chengx@chromium.org
+finnur@chromium.org
 grt@chromium.org
 robliao@chromium.org
diff --git a/chrome/renderer/benchmarking_extension.cc b/chrome/renderer/benchmarking_extension.cc
index b0fe829..2d957fd 100644
--- a/chrome/renderer/benchmarking_extension.cc
+++ b/chrome/renderer/benchmarking_extension.cc
@@ -54,10 +54,14 @@
       v8::Isolate* isolate,
       v8::Local<v8::String> name) override {
     if (name->StringEquals(
-            v8::String::NewFromUtf8(isolate, "IsSingleProcess"))) {
+            v8::String::NewFromUtf8(isolate, "IsSingleProcess",
+                                    v8::NewStringType::kInternalized)
+                .ToLocalChecked())) {
       return v8::FunctionTemplate::New(isolate, IsSingleProcess);
     } else if (name->StringEquals(
-                   v8::String::NewFromUtf8(isolate, "HiResTime"))) {
+                   v8::String::NewFromUtf8(isolate, "HiResTime",
+                                           v8::NewStringType::kInternalized)
+                       .ToLocalChecked())) {
       return v8::FunctionTemplate::New(isolate, HiResTime);
     }
 
diff --git a/chrome/renderer/extensions/app_bindings.cc b/chrome/renderer/extensions/app_bindings.cc
index 434c2ac..e44d35e8 100644
--- a/chrome/renderer/extensions/app_bindings.cc
+++ b/chrome/renderer/extensions/app_bindings.cc
@@ -55,8 +55,11 @@
 
 void AppBindings::GetRunningState(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
-  args.GetReturnValue().Set(v8::String::NewFromUtf8(
-      context()->isolate(), app_core_.GetRunningState(context())));
+  args.GetReturnValue().Set(
+      v8::String::NewFromUtf8(context()->isolate(),
+                              app_core_.GetRunningState(context()),
+                              v8::NewStringType::kInternalized)
+          .ToLocalChecked());
 }
 
 void AppBindings::OnAppInstallStateResponse(int callback_id,
@@ -68,9 +71,10 @@
   v8::HandleScope handle_scope(isolate);
   v8::Context::Scope context_scope(context()->v8_context());
   v8::Local<v8::Value> argv[] = {
-    v8::String::NewFromUtf8(isolate, state.c_str()),
-    v8::Integer::New(isolate, callback_id)
-  };
+      v8::String::NewFromUtf8(isolate, state.c_str(),
+                              v8::NewStringType::kNormal)
+          .ToLocalChecked(),
+      v8::Integer::New(isolate, callback_id)};
   context()->module_system()->CallModuleMethodSafe(
       "app", "onInstallStateResponse", arraysize(argv), argv);
 }
diff --git a/chrome/renderer/extensions/automation_internal_custom_bindings.cc b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
index f52bc2e..c145cee5 100644
--- a/chrome/renderer/extensions/automation_internal_custom_bindings.cc
+++ b/chrome/renderer/extensions/automation_internal_custom_bindings.cc
@@ -73,7 +73,7 @@
   while (node && !ui::IsTableLikeRole(node->data().role))
     node = node->parent();
 
-  if (ui::IsTableLikeRole(node->data().role))
+  if (node && ui::IsTableLikeRole(node->data().role))
     return node;
 
   return nullptr;
@@ -481,17 +481,21 @@
                                       AutomationAXTreeWrapper* tree_wrapper) {
     result.Set(v8::Integer::New(isolate, tree_wrapper->tree()->root()->id()));
   });
-  RouteTreeIDFunction(
-      "GetDocURL", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
-                      AutomationAXTreeWrapper* tree_wrapper) {
-        result.Set(v8::String::NewFromUtf8(
-            isolate, tree_wrapper->tree()->data().url.c_str()));
-      });
+  RouteTreeIDFunction("GetDocURL", [](v8::Isolate* isolate,
+                                      v8::ReturnValue<v8::Value> result,
+                                      AutomationAXTreeWrapper* tree_wrapper) {
+    result.Set(v8::String::NewFromUtf8(isolate,
+                                       tree_wrapper->tree()->data().url.c_str(),
+                                       v8::NewStringType::kNormal)
+                   .ToLocalChecked());
+  });
   RouteTreeIDFunction(
       "GetDocTitle", [](v8::Isolate* isolate, v8::ReturnValue<v8::Value> result,
                         AutomationAXTreeWrapper* tree_wrapper) {
         result.Set(v8::String::NewFromUtf8(
-            isolate, tree_wrapper->tree()->data().title.c_str()));
+                       isolate, tree_wrapper->tree()->data().title.c_str(),
+                       v8::NewStringType::kNormal)
+                       .ToLocalChecked());
       });
   RouteTreeIDFunction(
       "GetDocLoaded",
@@ -609,7 +613,9 @@
         }
 
         std::string role_name = ui::ToString(mapped_role);
-        result.Set(v8::String::NewFromUtf8(isolate, role_name.c_str()));
+        result.Set(v8::String::NewFromUtf8(isolate, role_name.c_str(),
+                                           v8::NewStringType::kNormal)
+                       .ToLocalChecked());
       });
   RouteNodeIDFunction(
       "GetLocation",
@@ -737,7 +743,9 @@
           return;
         }
 
-        result.Set(v8::String::NewFromUtf8(isolate, attr_value.c_str()));
+        result.Set(v8::String::NewFromUtf8(isolate, attr_value.c_str(),
+                                           v8::NewStringType::kNormal)
+                       .ToLocalChecked());
       });
   RouteNodeIDPlusAttributeFunction(
       "GetBoolAttribute",
@@ -845,7 +853,9 @@
         if (!node->data().GetHtmlAttribute(attribute_name.c_str(), &attr_value))
           return;
 
-        result.Set(v8::String::NewFromUtf8(isolate, attr_value.c_str()));
+        result.Set(v8::String::NewFromUtf8(isolate, attr_value.c_str(),
+                                           v8::NewStringType::kNormal)
+                       .ToLocalChecked());
       });
   RouteNodeIDFunction(
       "GetNameFrom",
@@ -854,7 +864,9 @@
         ax::mojom::NameFrom name_from = static_cast<ax::mojom::NameFrom>(
             node->data().GetIntAttribute(ax::mojom::IntAttribute::kNameFrom));
         std::string name_from_str = ui::ToString(name_from);
-        result.Set(v8::String::NewFromUtf8(isolate, name_from_str.c_str()));
+        result.Set(v8::String::NewFromUtf8(isolate, name_from_str.c_str(),
+                                           v8::NewStringType::kNormal)
+                       .ToLocalChecked());
       });
   RouteNodeIDFunction("GetSubscript", [](v8::Isolate* isolate,
                                          v8::ReturnValue<v8::Value> result,
@@ -970,7 +982,9 @@
         for (size_t i = 0; i < standard_actions.size(); i++) {
           const v8::Maybe<bool>& did_set_value = actions_result->Set(
               isolate->GetCurrentContext(), i,
-              v8::String::NewFromUtf8(isolate, standard_actions[i].c_str()));
+              v8::String::NewFromUtf8(isolate, standard_actions[i].c_str(),
+                                      v8::NewStringType::kNormal)
+                  .ToLocalChecked());
 
           bool did_set_value_result = false;
           if (!did_set_value.To(&did_set_value_result) || !did_set_value_result)
@@ -987,7 +1001,9 @@
                 ax::mojom::IntAttribute::kCheckedState));
         if (checked_state != ax::mojom::CheckedState::kNone) {
           const std::string checked_str = ui::ToString(checked_state);
-          result.Set(v8::String::NewFromUtf8(isolate, checked_str.c_str()));
+          result.Set(v8::String::NewFromUtf8(isolate, checked_str.c_str(),
+                                             v8::NewStringType::kNormal)
+                         .ToLocalChecked());
         }
       });
   RouteNodeIDFunction(
@@ -998,7 +1014,9 @@
             node->data().GetRestriction();
         if (restriction != ax::mojom::Restriction::kNone) {
           const std::string restriction_str = ui::ToString(restriction);
-          result.Set(v8::String::NewFromUtf8(isolate, restriction_str.c_str()));
+          result.Set(v8::String::NewFromUtf8(isolate, restriction_str.c_str(),
+                                             v8::NewStringType::kNormal)
+                         .ToLocalChecked());
         }
       });
   RouteNodeIDFunction(
@@ -1010,8 +1028,10 @@
                 node->data().GetIntAttribute(
                     ax::mojom::IntAttribute::kDefaultActionVerb));
         std::string default_action_verb_str = ui::ToString(default_action_verb);
-        result.Set(
-            v8::String::NewFromUtf8(isolate, default_action_verb_str.c_str()));
+        result.Set(v8::String::NewFromUtf8(isolate,
+                                           default_action_verb_str.c_str(),
+                                           v8::NewStringType::kNormal)
+                       .ToLocalChecked());
       });
   RouteNodeIDPlusStringBoolFunction(
       "GetNextTextMatch",
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.cc b/chrome/renderer/extensions/cast_streaming_native_handler.cc
index eea058b..eb57fda 100644
--- a/chrome/renderer/extensions/cast_streaming_native_handler.cc
+++ b/chrome/renderer/extensions/cast_streaming_native_handler.cc
@@ -105,8 +105,10 @@
   if (config->sender_ssrc == config->receiver_ssrc) {
     DVLOG(1) << "sender_ssrc " << config->sender_ssrc
              << " cannot be equal to receiver_ssrc";
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return false;
   }
   config->min_playout_delay = base::TimeDelta::FromMilliseconds(
@@ -120,23 +122,29 @@
   if (config->min_playout_delay <= base::TimeDelta()) {
     DVLOG(1) << "min_playout_delay " << config->min_playout_delay
              << " must be greater than zero";
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return false;
   }
   if (config->min_playout_delay > config->max_playout_delay) {
     DVLOG(1) << "min_playout_delay " << config->min_playout_delay
              << " must be less than or equal to max_palyout_delay";
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return false;
   }
   if (config->animated_playout_delay < config->min_playout_delay ||
       config->animated_playout_delay > config->max_playout_delay) {
     DVLOG(1) << "animated_playout_delay " << config->animated_playout_delay
              << " must be between (inclusive) the min and max playout delay";
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return false;
   }
   if (ext_params.codec_name == kCodecNameOpus) {
@@ -156,13 +164,17 @@
       default:
         DVLOG(1) << "rtp_timebase " << config->rtp_timebase << " is invalid";
         isolate->ThrowException(v8::Exception::Error(
-            v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+            v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                    v8::NewStringType::kNormal)
+                .ToLocalChecked()));
         return false;
     }
     config->channels = ext_params.channels ? *ext_params.channels : 2;
     if (config->channels != 1 && config->channels != 2) {
       isolate->ThrowException(v8::Exception::Error(
-          v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+          v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                  v8::NewStringType::kNormal)
+              .ToLocalChecked()));
       DVLOG(1) << "channels " << config->channels << " is invalid";
       return false;
     }
@@ -177,7 +189,9 @@
     config->channels = ext_params.channels ? *ext_params.channels : 1;
     if (config->channels != 1) {
       isolate->ThrowException(v8::Exception::Error(
-          v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+          v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                  v8::NewStringType::kNormal)
+              .ToLocalChecked()));
       DVLOG(1) << "channels " << config->channels << " is invalid";
       return false;
     }
@@ -191,7 +205,9 @@
       DVLOG(1) << "min_bitrate " << config->min_bitrate << " is larger than "
                << "max_bitrate " << config->max_bitrate;
       isolate->ThrowException(v8::Exception::Error(
-          v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+          v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                  v8::NewStringType::kNormal)
+              .ToLocalChecked()));
       return false;
     }
     config->start_bitrate = config->min_bitrate;
@@ -200,7 +216,9 @@
     if (config->max_frame_rate > media::limits::kMaxFramesPerSecond) {
       DVLOG(1) << "max_frame_rate " << config->max_frame_rate << " is invalid";
       isolate->ThrowException(v8::Exception::Error(
-          v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+          v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                  v8::NewStringType::kNormal)
+              .ToLocalChecked()));
       return false;
     }
     if (ext_params.codec_name == kCodecNameVp8) {
@@ -225,19 +243,25 @@
     config->codec = media::cast::CODEC_VIDEO_REMOTE;
   } else {
     DVLOG(1) << "codec_name " << ext_params.codec_name << " is invalid";
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return false;
   }
   if (ext_params.aes_key && !HexDecode(*ext_params.aes_key, &config->aes_key)) {
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesKey,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return false;
   }
   if (ext_params.aes_iv_mask &&
       !HexDecode(*ext_params.aes_iv_mask, &config->aes_iv_mask)) {
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesIvMask,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return false;
   }
   return true;
@@ -398,7 +422,9 @@
           blink::WebDOMMediaStreamTrack::FromV8Value(args[0]);
       if (track.IsNull()) {
         isolate->ThrowException(v8::Exception::Error(
-            v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+            v8::String::NewFromUtf8(isolate, kInvalidStreamArgs,
+                                    v8::NewStringType::kNormal)
+                .ToLocalChecked()));
         return;
       }
       stream1.reset(new CastRtpStream(track.Component(), session));
@@ -409,7 +435,9 @@
           blink::WebDOMMediaStreamTrack::FromV8Value(args[1]);
       if (track.IsNull()) {
         isolate->ThrowException(v8::Exception::Error(
-            v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+            v8::String::NewFromUtf8(isolate, kInvalidStreamArgs,
+                                    v8::NewStringType::kNormal)
+                .ToLocalChecked()));
         return;
       }
       stream2.reset(new CastRtpStream(track.Component(), session));
@@ -533,13 +561,17 @@
       V8ValueConverter::Create()->FromV8Value(args[1], context()->v8_context());
   if (!params_value) {
     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams)));
+        v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertParams,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
   std::unique_ptr<RtpParams> params = RtpParams::FromValue(*params_value);
   if (!params) {
     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams)));
+        v8::String::NewFromUtf8(args.GetIsolate(), kInvalidRtpParams,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
 
@@ -629,7 +661,9 @@
           args[1], context()->v8_context()));
   if (!options) {
     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
+        v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
   transport->SetOptions(std::move(options));
@@ -743,8 +777,10 @@
   if (iter != rtp_stream_map_.end())
     return iter->second.get();
   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
-  isolate->ThrowException(v8::Exception::RangeError(v8::String::NewFromUtf8(
-      isolate, kRtpStreamNotFound)));
+  isolate->ThrowException(v8::Exception::RangeError(
+      v8::String::NewFromUtf8(isolate, kRtpStreamNotFound,
+                              v8::NewStringType::kNormal)
+          .ToLocalChecked()));
   return NULL;
 }
 
@@ -756,7 +792,9 @@
     return iter->second.get();
   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
   isolate->ThrowException(v8::Exception::RangeError(
-      v8::String::NewFromUtf8(isolate, kUdpTransportNotFound)));
+      v8::String::NewFromUtf8(isolate, kUdpTransportNotFound,
+                              v8::NewStringType::kNormal)
+          .ToLocalChecked()));
   return NULL;
 }
 
@@ -768,14 +806,18 @@
       V8ValueConverter::Create()->FromV8Value(arg, context()->v8_context());
   if (!params_value) {
     isolate->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(isolate, kUnableToConvertParams)));
+        v8::String::NewFromUtf8(isolate, kUnableToConvertParams,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return false;
   }
   std::unique_ptr<RtpReceiverParams> params =
       RtpReceiverParams::FromValue(*params_value);
   if (!params) {
     isolate->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(isolate, kInvalidRtpParams)));
+        v8::String::NewFromUtf8(isolate, kInvalidRtpParams,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return false;
   }
 
@@ -784,7 +826,9 @@
   config->rtp_max_delay_ms = params->max_latency;
   if (config->rtp_max_delay_ms < 0 || config->rtp_max_delay_ms > 1000) {
     isolate->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(isolate, kInvalidLatency)));
+        v8::String::NewFromUtf8(isolate, kInvalidLatency,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return false;
   }
   config->channels = 2;
@@ -813,20 +857,26 @@
     config->rtp_timebase = *params->rtp_timebase;
     if (config->rtp_timebase < 1000 || config->rtp_timebase > 1000000) {
       isolate->ThrowException(v8::Exception::TypeError(
-          v8::String::NewFromUtf8(isolate, kInvalidRtpTimebase)));
+          v8::String::NewFromUtf8(isolate, kInvalidRtpTimebase,
+                                  v8::NewStringType::kNormal)
+              .ToLocalChecked()));
       return false;
     }
   }
   if (params->aes_key &&
       !HexDecode(*params->aes_key, &config->aes_key)) {
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidAesKey)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesKey,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return false;
   }
   if (params->aes_iv_mask &&
       !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) {
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesIvMask,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return false;
   }
   return true;
@@ -840,20 +890,26 @@
       V8ValueConverter::Create()->FromV8Value(arg, context()->v8_context());
   if (!destination_value) {
     isolate->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(isolate, kInvalidAesIvMask)));
+        v8::String::NewFromUtf8(isolate, kInvalidAesIvMask,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return false;
   }
   std::unique_ptr<IPEndPoint> destination =
       IPEndPoint::FromValue(*destination_value);
   if (!destination) {
     isolate->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(isolate, kInvalidDestination)));
+        v8::String::NewFromUtf8(isolate, kInvalidDestination,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return false;
   }
   net::IPAddress ip;
   if (!ip.AssignFromIPLiteral(destination->address)) {
     isolate->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(isolate, kInvalidDestination)));
+        v8::String::NewFromUtf8(isolate, kInvalidDestination,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return false;
   }
   *ip_endpoint = net::IPEndPoint(ip, destination->port);
@@ -871,7 +927,9 @@
       !args[5]->IsNumber() ||
       !args[6]->IsString()) {
     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
+        v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
 
@@ -896,7 +954,9 @@
 
   if (fps <= 1) {
     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS)));
+        v8::String::NewFromUtf8(args.GetIsolate(), kInvalidFPS,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
 
@@ -906,7 +966,9 @@
 
   if (stream.IsNull()) {
     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL)));
+        v8::String::NewFromUtf8(args.GetIsolate(), kInvalidMediaStreamURL,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
 
@@ -925,7 +987,9 @@
 
   if (!params.IsValid()) {
     args.GetIsolate()->ThrowException(v8::Exception::TypeError(
-        v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams)));
+        v8::String::NewFromUtf8(args.GetIsolate(), kInvalidAudioParams,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
 
@@ -938,7 +1002,9 @@
       options = base::DictionaryValue::From(std::move(options_value));
       if (!options) {
         args.GetIsolate()->ThrowException(v8::Exception::TypeError(
-            v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs)));
+            v8::String::NewFromUtf8(args.GetIsolate(), kUnableToConvertArgs,
+                                    v8::NewStringType::kNormal)
+                .ToLocalChecked()));
         return;
       }
     }
@@ -965,10 +1031,10 @@
     v8::CopyablePersistentTraits<v8::Function>::CopyablePersistent function,
     const std::string& error_message) {
   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
-  v8::Local<v8::Value> arg = v8::String::NewFromUtf8(isolate,
-                                                      error_message.data(),
-                                                      v8::String::kNormalString,
-                                                      error_message.size());
+  v8::Local<v8::Value> arg =
+      v8::String::NewFromUtf8(isolate, error_message.data(),
+                              v8::NewStringType::kNormal, error_message.size())
+          .ToLocalChecked();
   context()->SafeCallFunction(v8::Local<v8::Function>::New(isolate, function),
                               1, &arg);
 }
diff --git a/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc b/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc
index 960ebbe..997f24ed 100644
--- a/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc
+++ b/chrome/renderer/extensions/file_browser_handler_custom_bindings.cc
@@ -39,15 +39,24 @@
     v8::Isolate* isolate = args.GetIsolate();
     std::string file_system_name(*v8::String::Utf8Value(
         isolate,
-        file_def->Get(v8::String::NewFromUtf8(isolate, "fileSystemName"))));
+        file_def->Get(v8::String::NewFromUtf8(isolate, "fileSystemName",
+                                              v8::NewStringType::kInternalized)
+                          .ToLocalChecked())));
     GURL file_system_root(*v8::String::Utf8Value(
         isolate,
-        file_def->Get(v8::String::NewFromUtf8(isolate, "fileSystemRoot"))));
+        file_def->Get(v8::String::NewFromUtf8(isolate, "fileSystemRoot",
+                                              v8::NewStringType::kInternalized)
+                          .ToLocalChecked())));
     std::string file_full_path(*v8::String::Utf8Value(
         isolate,
-        file_def->Get(v8::String::NewFromUtf8(isolate, "fileFullPath"))));
+        file_def->Get(v8::String::NewFromUtf8(isolate, "fileFullPath",
+                                              v8::NewStringType::kInternalized)
+                          .ToLocalChecked())));
     bool is_directory =
-        file_def->Get(v8::String::NewFromUtf8(isolate, "fileIsDirectory"))
+        file_def
+            ->Get(v8::String::NewFromUtf8(isolate, "fileIsDirectory",
+                                          v8::NewStringType::kInternalized)
+                      .ToLocalChecked())
             ->BooleanValue(context->v8_context())
             .FromMaybe(false);
     blink::WebDOMFileSystem::EntryType entry_type =
diff --git a/chrome/renderer/extensions/webstore_bindings.cc b/chrome/renderer/extensions/webstore_bindings.cc
index ff95be9..bbbda3c 100644
--- a/chrome/renderer/extensions/webstore_bindings.cc
+++ b/chrome/renderer/extensions/webstore_bindings.cc
@@ -75,10 +75,13 @@
   v8::Context::Scope context_scope(context()->v8_context());
   v8::Local<v8::Value> argv[] = {
       v8::Integer::New(isolate, install_id), v8::Boolean::New(isolate, success),
-      v8::String::NewFromUtf8(isolate, error.c_str()),
+      v8::String::NewFromUtf8(isolate, error.c_str(),
+                              v8::NewStringType::kNormal)
+          .ToLocalChecked(),
       v8::String::NewFromUtf8(
-          isolate,
-          api::webstore::kInstallResultCodes[static_cast<int>(result)])};
+          isolate, api::webstore::kInstallResultCodes[static_cast<int>(result)],
+          v8::NewStringType::kNormal)
+          .ToLocalChecked()};
   context()->module_system()->CallModuleMethodSafe(
       "webstore", "onInstallResponse", arraysize(argv), argv);
 }
@@ -98,7 +101,8 @@
   v8::HandleScope handle_scope(isolate);
   v8::Context::Scope context_scope(context()->v8_context());
   v8::Local<v8::Value> argv[] = {
-      v8::String::NewFromUtf8(isolate, stage_string)};
+      v8::String::NewFromUtf8(isolate, stage_string, v8::NewStringType::kNormal)
+          .ToLocalChecked()};
   context()->module_system()->CallModuleMethodSafe(
       "webstore", "onInstallStageChanged", arraysize(argv), argv);
 }
@@ -143,7 +147,9 @@
   if (!GetWebstoreItemIdFromFrame(
       frame, preferred_store_link_url, &webstore_item_id, &error)) {
     args.GetIsolate()->ThrowException(
-        v8::String::NewFromUtf8(args.GetIsolate(), error.c_str()));
+        v8::String::NewFromUtf8(args.GetIsolate(), error.c_str(),
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked());
     return;
   }
 
diff --git a/chrome/renderer/loadtimes_extension_bindings.cc b/chrome/renderer/loadtimes_extension_bindings.cc
index dda7d71..a79a0a2d 100644
--- a/chrome/renderer/loadtimes_extension_bindings.cc
+++ b/chrome/renderer/loadtimes_extension_bindings.cc
@@ -64,9 +64,15 @@
   v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
       v8::Isolate* isolate,
       v8::Local<v8::String> name) override {
-    if (name->StringEquals(v8::String::NewFromUtf8(isolate, "GetLoadTimes"))) {
+    if (name->StringEquals(
+            v8::String::NewFromUtf8(isolate, "GetLoadTimes",
+                                    v8::NewStringType::kInternalized)
+                .ToLocalChecked())) {
       return v8::FunctionTemplate::New(isolate, GetLoadTimes);
-    } else if (name->StringEquals(v8::String::NewFromUtf8(isolate, "GetCSI"))) {
+    } else if (name->StringEquals(
+                   v8::String::NewFromUtf8(isolate, "GetCSI",
+                                           v8::NewStringType::kInternalized)
+                       .ToLocalChecked())) {
       return v8::FunctionTemplate::New(isolate, GetCSI);
     }
     return v8::Local<v8::FunctionTemplate>();
diff --git a/chrome/renderer/net_benchmarking_extension.cc b/chrome/renderer/net_benchmarking_extension.cc
index a43add3..37f75e87 100644
--- a/chrome/renderer/net_benchmarking_extension.cc
+++ b/chrome/renderer/net_benchmarking_extension.cc
@@ -48,16 +48,25 @@
   v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
       v8::Isolate* isolate,
       v8::Local<v8::String> name) override {
-    if (name->StringEquals(v8::String::NewFromUtf8(isolate, "ClearCache"))) {
+    if (name->StringEquals(
+            v8::String::NewFromUtf8(isolate, "ClearCache",
+                                    v8::NewStringType::kInternalized)
+                .ToLocalChecked())) {
       return v8::FunctionTemplate::New(isolate, ClearCache);
-    } else if (name->StringEquals(v8::String::NewFromUtf8(
-                   isolate, "ClearHostResolverCache"))) {
+    } else if (name->StringEquals(
+                   v8::String::NewFromUtf8(isolate, "ClearHostResolverCache",
+                                           v8::NewStringType::kInternalized)
+                       .ToLocalChecked())) {
       return v8::FunctionTemplate::New(isolate, ClearHostResolverCache);
     } else if (name->StringEquals(
-                   v8::String::NewFromUtf8(isolate, "ClearPredictorCache"))) {
+                   v8::String::NewFromUtf8(isolate, "ClearPredictorCache",
+                                           v8::NewStringType::kInternalized)
+                       .ToLocalChecked())) {
       return v8::FunctionTemplate::New(isolate, ClearPredictorCache);
     } else if (name->StringEquals(
-                   v8::String::NewFromUtf8(isolate, "CloseConnections"))) {
+                   v8::String::NewFromUtf8(isolate, "CloseConnections",
+                                           v8::NewStringType::kInternalized)
+                       .ToLocalChecked())) {
       return v8::FunctionTemplate::New(isolate, CloseConnections);
     }
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 401aa4a..d11517d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -744,6 +744,7 @@
       "../browser/renderer_context_menu/spelling_menu_observer_browsertest.cc",
       "../browser/renderer_host/render_process_host_chrome_browsertest.cc",
       "../browser/repost_form_warning_browsertest.cc",
+      "../browser/resource_coordinator/discard_before_unload_helper_browsertest.cc",
       "../browser/resource_coordinator/local_site_characteristics_data_store_factory_browsertest.cc",
       "../browser/resource_coordinator/local_site_characteristics_data_unittest_utils.cc",
       "../browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h",
@@ -1965,8 +1966,6 @@
         "../browser/ui/cocoa/accelerators_cocoa_browsertest.mm",
         "../browser/ui/cocoa/apps/app_shim_menu_controller_mac_browsertest.mm",
         "../browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm",
-        "../browser/ui/cocoa/dev_tools_controller_browsertest.mm",
-        "../browser/ui/cocoa/omnibox/omnibox_view_mac_browsertest.mm",
         "../browser/ui/cocoa/permission_bubble/permission_bubble_views_cocoa_browsertest.mm",
         "../browser/ui/cocoa/renderer_context_menu/render_view_context_menu_mac_cocoa_browsertest.mm",
         "../browser/ui/cocoa/ssl_client_certificate_selector_cocoa_browsertest.mm",
@@ -2681,8 +2680,8 @@
     "../browser/subresource_filter/subresource_filter_test_harness.cc",
     "../browser/subresource_filter/subresource_filter_test_harness.h",
     "../browser/subresource_filter/subresource_filter_unittest.cc",
-    "../browser/sync/chrome_sync_client_unittest.cc",
     "../browser/sync/profile_sync_service_factory_unittest.cc",
+    "../browser/sync/session_sync_service_factory_unittest.cc",
     "../browser/sync/sessions/sync_sessions_web_contents_router_unittest.cc",
     "../browser/sync/sync_startup_tracker_unittest.cc",
     "../browser/thumbnails/thumbnail_service_unittest.cc",
@@ -4128,7 +4127,6 @@
         "../browser/ui/cocoa/browser_window_controller_unittest.mm",
         "../browser/ui/cocoa/browser_window_layout_unittest.mm",
         "../browser/ui/cocoa/browser_window_utils_unittest.mm",
-        "../browser/ui/cocoa/bubble_view_unittest.mm",
         "../browser/ui/cocoa/chrome_browser_window_unittest.mm",
         "../browser/ui/cocoa/clickhold_button_cell_unittest.mm",
         "../browser/ui/cocoa/color_panel_cocoa_unittest.mm",
@@ -4148,11 +4146,6 @@
         "../browser/ui/cocoa/history_overlay_controller_unittest.mm",
         "../browser/ui/cocoa/hover_close_button_unittest.mm",
         "../browser/ui/cocoa/image_button_cell_unittest.mm",
-        "../browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm",
-        "../browser/ui/cocoa/location_bar/autocomplete_text_field_editor_unittest.mm",
-        "../browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm",
-        "../browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.h",
-        "../browser/ui/cocoa/location_bar/autocomplete_text_field_unittest_helper.mm",
         "../browser/ui/cocoa/main_menu_builder_unittest.mm",
         "../browser/ui/cocoa/media_picker/desktop_media_picker_controller_unittest.mm",
         "../browser/ui/cocoa/menu_button_unittest.mm",
@@ -4160,16 +4153,10 @@
         "../browser/ui/cocoa/notifications/notification_response_builder_mac_unittest.mm",
         "../browser/ui/cocoa/nsmenuitem_additions_unittest.mm",
         "../browser/ui/cocoa/nsview_additions_unittest.mm",
-        "../browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm",
-        "../browser/ui/cocoa/omnibox/omnibox_popup_matrix_unittest.mm",
-        "../browser/ui/cocoa/omnibox/omnibox_popup_separator_view_unittest.mm",
-        "../browser/ui/cocoa/omnibox/omnibox_popup_view_mac_unittest.mm",
-        "../browser/ui/cocoa/omnibox/omnibox_view_mac_unittest.mm",
         "../browser/ui/cocoa/page_info/page_info_bubble_controller_unittest.mm",
         "../browser/ui/cocoa/profiles/profile_menu_controller_unittest.mm",
         "../browser/ui/cocoa/scoped_menu_bar_lock_unittest.mm",
         "../browser/ui/cocoa/spinner_view_unittest.mm",
-        "../browser/ui/cocoa/status_bubble_mac_unittest.mm",
         "../browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm",
         "../browser/ui/cocoa/styled_text_field_cell_unittest.mm",
         "../browser/ui/cocoa/styled_text_field_unittest.mm",
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc
index 25c9c2e..4af45fe 100644
--- a/chrome/test/base/test_browser_window.cc
+++ b/chrome/test/base/test_browser_window.cc
@@ -76,6 +76,11 @@
     content::WebContents* web_contents,
     float ratio) {}
 
+bool TestBrowserWindow::DoBrowserControlsShrinkRendererSize(
+    const content::WebContents* contents) const {
+  return false;
+}
+
 int TestBrowserWindow::GetTopControlsHeight() const {
   return 0;
 }
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index 45e8111..7e9cbb0 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -53,6 +53,8 @@
   gfx::NativeWindow GetNativeWindow() const override;
   void SetTopControlsShownRatio(content::WebContents* web_contents,
                                 float ratio) override;
+  bool DoBrowserControlsShrinkRendererSize(
+      const content::WebContents* contents) const override;
   int GetTopControlsHeight() const override;
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
   StatusBubble* GetStatusBubble() override;
diff --git a/chrome/test/base/v8_unit_test.cc b/chrome/test/base/v8_unit_test.cc
index 23cd96a..7f8ed5b 100644
--- a/chrome/test/base/v8_unit_test.cc
+++ b/chrome/test/base/v8_unit_test.cc
@@ -98,8 +98,10 @@
   v8::MicrotasksScope microtasks(
       isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
 
-  v8::Local<v8::Value> function_property =
-      context->Global()->Get(v8::String::NewFromUtf8(isolate, "runTest"));
+  v8::Local<v8::Value> function_property = context->Global()->Get(
+      v8::String::NewFromUtf8(isolate, "runTest",
+                              v8::NewStringType::kInternalized)
+          .ToLocalChecked());
   EXPECT_FALSE(function_property.IsEmpty());
   if (::testing::Test::HasNonfatalFailure())
     return false;
@@ -110,19 +112,19 @@
       v8::Local<v8::Function>::Cast(function_property);
 
   v8::Local<v8::Array> params = v8::Array::New(isolate);
-  params->Set(0,
-              v8::String::NewFromUtf8(isolate,
-                                      test_fixture.data(),
-                                      v8::String::kNormalString,
-                                      test_fixture.size()));
-  params->Set(1,
-              v8::String::NewFromUtf8(isolate,
-                                      test_name.data(),
-                                      v8::String::kNormalString,
-                                      test_name.size()));
+  params->Set(0, v8::String::NewFromUtf8(isolate, test_fixture.data(),
+                                         v8::NewStringType::kNormal,
+                                         test_fixture.size())
+                     .ToLocalChecked());
+  params->Set(
+      1, v8::String::NewFromUtf8(isolate, test_name.data(),
+                                 v8::NewStringType::kNormal, test_name.size())
+             .ToLocalChecked());
   v8::Local<v8::Value> args[] = {
       v8::Boolean::New(isolate, false),
-      v8::String::NewFromUtf8(isolate, "RUN_TEST_F"), params};
+      v8::String::NewFromUtf8(isolate, "RUN_TEST_F", v8::NewStringType::kNormal)
+          .ToLocalChecked(),
+      params};
 
   v8::TryCatch try_catch(isolate);
   v8::Local<v8::Value> result = function->Call(context->Global(), 3, args);
@@ -167,7 +169,9 @@
 void V8UnitTest::SetUp() {
   v8::Isolate* isolate = blink::MainThreadIsolate();
   v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
-  v8::Local<v8::String> log_string = v8::String::NewFromUtf8(isolate, "log");
+  v8::Local<v8::String> log_string =
+      v8::String::NewFromUtf8(isolate, "log", v8::NewStringType::kInternalized)
+          .ToLocalChecked();
   v8::Local<v8::FunctionTemplate> log_function =
       v8::FunctionTemplate::New(isolate, &V8UnitTest::Log);
   log_function->RemovePrototype();
@@ -175,29 +179,50 @@
 
   // Set up chrome object for chrome.send().
   v8::Local<v8::ObjectTemplate> chrome = v8::ObjectTemplate::New(isolate);
-  global->Set(v8::String::NewFromUtf8(isolate, "chrome"), chrome);
+  global->Set(v8::String::NewFromUtf8(isolate, "chrome",
+                                      v8::NewStringType::kInternalized)
+                  .ToLocalChecked(),
+              chrome);
   v8::Local<v8::FunctionTemplate> send_function =
       v8::FunctionTemplate::New(isolate, &V8UnitTest::ChromeSend);
   send_function->RemovePrototype();
-  chrome->Set(v8::String::NewFromUtf8(isolate, "send"), send_function);
+  chrome->Set(
+      v8::String::NewFromUtf8(isolate, "send", v8::NewStringType::kInternalized)
+          .ToLocalChecked(),
+      send_function);
 
   context_.Reset(isolate, v8::Context::New(isolate, NULL, global));
 
   // Set up console object for console.log(), etc.
   v8::Local<v8::ObjectTemplate> console = v8::ObjectTemplate::New(isolate);
-  global->Set(v8::String::NewFromUtf8(isolate, "console"), console);
+  global->Set(v8::String::NewFromUtf8(isolate, "console",
+                                      v8::NewStringType::kInternalized)
+                  .ToLocalChecked(),
+              console);
   console->Set(log_string, log_function);
-  console->Set(v8::String::NewFromUtf8(isolate, "info"), log_function);
-  console->Set(v8::String::NewFromUtf8(isolate, "warn"), log_function);
+  console->Set(
+      v8::String::NewFromUtf8(isolate, "info", v8::NewStringType::kInternalized)
+          .ToLocalChecked(),
+      log_function);
+  console->Set(
+      v8::String::NewFromUtf8(isolate, "warn", v8::NewStringType::kInternalized)
+          .ToLocalChecked(),
+      log_function);
   v8::Local<v8::FunctionTemplate> error_function =
       v8::FunctionTemplate::New(isolate, &V8UnitTest::Error);
   error_function->RemovePrototype();
-  console->Set(v8::String::NewFromUtf8(isolate, "error"), error_function);
+  console->Set(v8::String::NewFromUtf8(isolate, "error",
+                                       v8::NewStringType::kInternalized)
+                   .ToLocalChecked(),
+               error_function);
   {
     v8::Local<v8::Context> context = context_.Get(isolate);
     v8::Context::Scope context_scope(context);
     context->Global()
-        ->Set(context, v8::String::NewFromUtf8(isolate, "console"),
+        ->Set(context,
+              v8::String::NewFromUtf8(isolate, "console",
+                                      v8::NewStringType::kInternalized)
+                  .ToLocalChecked(),
               console->NewInstance(context).ToLocalChecked())
         .ToChecked();
   }
@@ -210,12 +235,13 @@
       v8::Local<v8::Context>::New(isolate, context_);
   v8::Context::Scope context_scope(context);
   context->Global()->Set(
-      v8::String::NewFromUtf8(isolate,
-                              var_name.c_str(),
-                              v8::String::kNormalString,
-                              var_name.length()),
-      v8::String::NewFromUtf8(
-          isolate, value.c_str(), v8::String::kNormalString, value.length()));
+      v8::String::NewFromUtf8(isolate, var_name.c_str(),
+                              v8::NewStringType::kInternalized,
+                              var_name.length())
+          .ToLocalChecked(),
+      v8::String::NewFromUtf8(isolate, value.c_str(),
+                              v8::NewStringType::kNormal, value.length())
+          .ToLocalChecked());
 }
 
 void V8UnitTest::ExecuteScriptInContext(const base::StringPiece& script_source,
@@ -228,15 +254,13 @@
   v8::MicrotasksScope microtasks(
       isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
   v8::Local<v8::String> source =
-      v8::String::NewFromUtf8(isolate,
-                              script_source.data(),
-                              v8::String::kNormalString,
-                              script_source.size());
+      v8::String::NewFromUtf8(isolate, script_source.data(),
+                              v8::NewStringType::kNormal, script_source.size())
+          .ToLocalChecked();
   v8::Local<v8::String> name =
-      v8::String::NewFromUtf8(isolate,
-                              script_name.data(),
-                              v8::String::kNormalString,
-                              script_name.size());
+      v8::String::NewFromUtf8(isolate, script_name.data(),
+                              v8::NewStringType::kNormal, script_name.size())
+          .ToLocalChecked();
 
   v8::TryCatch try_catch(isolate);
   v8::ScriptOrigin origin(name);
@@ -283,7 +307,9 @@
       isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
 
   v8::Local<v8::Value> function_property = context->Global()->Get(
-      v8::String::NewFromUtf8(isolate, function_name.c_str()));
+      v8::String::NewFromUtf8(isolate, function_name.c_str(),
+                              v8::NewStringType::kInternalized)
+          .ToLocalChecked());
   ASSERT_FALSE(function_property.IsEmpty());
   ASSERT_TRUE(function_property->IsFunction());
   v8::Local<v8::Function> function =
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index 3849b02..c4e50e8 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -197,22 +197,26 @@
 Status ParsePageLoadStrategy(const base::Value& option,
                              Capabilities* capabilities) {
   if (!option.GetAsString(&capabilities->page_load_strategy))
-    return Status(kUnknownError, "must be a string");
-  if (capabilities->page_load_strategy == PageLoadStrategy::kNormal ||
-      capabilities->page_load_strategy == PageLoadStrategy::kNone)
+    return Status(kInvalidArgument, "'pageLoadStrategy' must be a string");
+  if (capabilities->page_load_strategy == PageLoadStrategy::kNone ||
+      capabilities->page_load_strategy == PageLoadStrategy::kEager ||
+      capabilities->page_load_strategy == PageLoadStrategy::kNormal)
     return Status(kOk);
-  return Status(kUnknownError, "page load strategy unsupported");
+  return Status(kInvalidArgument, "invalid 'pageLoadStrategy'");
 }
 
-Status ParseUnexpectedAlertBehaviour(const base::Value& option,
-                             Capabilities* capabilities) {
-  if (!option.GetAsString(&capabilities->unexpected_alert_behaviour))
-    return Status(kUnknownError, "must be a string");
-  if (capabilities->unexpected_alert_behaviour == kAccept ||
-      capabilities->unexpected_alert_behaviour == kDismiss ||
-      capabilities->unexpected_alert_behaviour == kIgnore)
+Status ParseUnhandledPromptBehavior(const base::Value& option,
+                                    Capabilities* capabilities) {
+  if (!option.GetAsString(&capabilities->unhandled_prompt_behavior))
+    return Status(kInvalidArgument,
+                  "'unhandledPromptBehavior' must be a string");
+  if (capabilities->unhandled_prompt_behavior == kDismiss ||
+      capabilities->unhandled_prompt_behavior == kAccept ||
+      capabilities->unhandled_prompt_behavior == kDismissAndNotify ||
+      capabilities->unhandled_prompt_behavior == kAcceptAndNotify ||
+      capabilities->unhandled_prompt_behavior == kIgnore)
     return Status(kOk);
-  return Status(kUnknownError, "unexpected alert behaviour unsupported");
+  return Status(kInvalidArgument, "invalid 'unhandledPromptBehavior'");
 }
 
 Status ParseSwitches(const base::Value& option,
@@ -669,13 +673,13 @@
 PerfLoggingPrefs::~PerfLoggingPrefs() {}
 
 Capabilities::Capabilities()
-    : android_use_running_app(false),
+    : accept_insecure_certs(false),
+      page_load_strategy(PageLoadStrategy::kNormal),
+      android_use_running_app(false),
       detach(false),
       extension_load_timeout(base::TimeDelta::FromSeconds(10)),
       force_devtools_screenshot(true),
-      page_load_strategy(PageLoadStrategy::kNormal),
       network_emulation_enabled(false),
-      accept_insecure_certs(false),
       use_automation_extension(true) {}
 
 Capabilities::~Capabilities() {}
@@ -690,29 +694,44 @@
 
 Status Capabilities::Parse(const base::DictionaryValue& desired_caps) {
   std::map<std::string, Parser> parser_map;
+
+  // W3C defined capabilities.
+  parser_map["acceptInsecureCerts"] =
+      base::BindRepeating(&ParseBoolean, &accept_insecure_certs);
+  parser_map["browserName"] = base::BindRepeating(&ParseString, &browser_name);
+  parser_map["browserVersion"] =
+      base::BindRepeating(&ParseString, &browser_version);
+  parser_map["platformName"] =
+      base::BindRepeating(&ParseString, &platform_name);
+  parser_map["pageLoadStrategy"] = base::BindRepeating(&ParsePageLoadStrategy);
+  parser_map["proxy"] = base::BindRepeating(&ParseProxy);
+  // TODO(https://crbug.com/chromedriver/1997): Parse "timeouts".
+  // TODO(https://crbug.com/chromedriver/2596): "unexpectedAlertBehaviour" is
+  // legacy name of "unhandledPromptBehavior", remove when we stop supporting
+  // legacy mode.
+  parser_map["unexpectedAlertBehaviour"] =
+      base::BindRepeating(&ParseUnhandledPromptBehavior);
+  parser_map["unhandledPromptBehavior"] =
+      base::BindRepeating(&ParseUnhandledPromptBehavior);
+
+  // ChromeDriver specific capabilities.
   // goog:chromeOptions is the current spec conformance, but chromeOptions is
   // still supported
   if (desired_caps.GetDictionary("goog:chromeOptions", nullptr)) {
-    parser_map["goog:chromeOptions"] = base::Bind(&ParseChromeOptions);
+    parser_map["goog:chromeOptions"] = base::BindRepeating(&ParseChromeOptions);
   } else {
-    parser_map["chromeOptions"] = base::Bind(&ParseChromeOptions);
+    parser_map["chromeOptions"] = base::BindRepeating(&ParseChromeOptions);
   }
-
-  parser_map["loggingPrefs"] = base::Bind(&ParseLoggingPrefs);
-  parser_map["proxy"] = base::Bind(&ParseProxy);
-  parser_map["pageLoadStrategy"] = base::Bind(&ParsePageLoadStrategy);
-  parser_map["unexpectedAlertBehaviour"] =
-      base::Bind(&ParseUnexpectedAlertBehaviour);
-  parser_map["acceptInsecureCerts"] =
-      base::BindRepeating(&ParseBoolean, &accept_insecure_certs);
+  parser_map["loggingPrefs"] = base::BindRepeating(&ParseLoggingPrefs);
   // Network emulation requires device mode, which is only enabled when
   // mobile emulation is on.
   if (desired_caps.GetDictionary("goog:chromeOptions.mobileEmulation",
                                  nullptr) ||
       desired_caps.GetDictionary("chromeOptions.mobileEmulation", nullptr)) {
     parser_map["networkConnectionEnabled"] =
-        base::Bind(&ParseBoolean, &network_emulation_enabled);
+        base::BindRepeating(&ParseBoolean, &network_emulation_enabled);
   }
+
   for (std::map<std::string, Parser>::iterator it = parser_map.begin();
        it != parser_map.end(); ++it) {
     const base::Value* capability = NULL;
@@ -750,3 +769,27 @@
   }
   return Status(kOk);
 }
+
+Status Capabilities::CheckSupport() const {
+  // TODO(https://crbug.com/chromedriver/1902): pageLoadStrategy=eager not yet
+  // supported.
+  if (page_load_strategy.length() > 0 &&
+      page_load_strategy != PageLoadStrategy::kNormal &&
+      page_load_strategy != PageLoadStrategy::kNone) {
+    return Status(kInvalidArgument, "'pageLoadStrategy=" + page_load_strategy +
+                                        "' not yet supported");
+  }
+
+  // TODO(https://crbug.com/chromedriver/2597): Some unhandledPromptBehavior
+  // modes not yet supported.
+  if (unhandled_prompt_behavior.length() > 0 &&
+      unhandled_prompt_behavior != kAccept &&
+      unhandled_prompt_behavior != kDismiss &&
+      unhandled_prompt_behavior != kIgnore) {
+    return Status(kInvalidArgument,
+                  "'unhandledPromptBehavior=" + unhandled_prompt_behavior +
+                      "' not yet supported");
+  }
+
+  return Status(kOk);
+}
diff --git a/chrome/test/chromedriver/capabilities.h b/chrome/test/chromedriver/capabilities.h
index 4ffbc38..425eeef1 100644
--- a/chrome/test/chromedriver/capabilities.h
+++ b/chrome/test/chromedriver/capabilities.h
@@ -96,8 +96,40 @@
   // Return true if android package is specified.
   bool IsAndroid() const;
 
+  // Accepts all W3C defined capabilities (including those not yet supported by
+  // ChromeDriver) and all ChromeDriver-specific extensions.
   Status Parse(const base::DictionaryValue& desired_caps);
 
+  // Check if all specified capabilities are supported by ChromeDriver.
+  // The long term goal is to support all standard capabilities, thus making
+  // this method unnecessary.
+  Status CheckSupport() const;
+
+  //
+  // W3C defined capabilities
+  //
+
+  bool accept_insecure_certs;
+
+  std::string browser_name;
+  std::string browser_version;
+  std::string platform_name;
+
+  std::string page_load_strategy;
+
+  // Data from "proxy" capability are stored in "switches" field.
+
+  // The default values for the timeout fields came from W3C spec.
+  base::TimeDelta script_timeout = base::TimeDelta::FromSeconds(30);
+  base::TimeDelta page_load_timeout = base::TimeDelta::FromSeconds(300);
+  base::TimeDelta implicit_wait_timeout = base::TimeDelta::FromSeconds(0);
+
+  std::string unhandled_prompt_behavior;
+
+  //
+  // ChromeDriver specific capabilities
+  //
+
   std::string android_activity;
 
   std::string android_device_serial;
@@ -147,14 +179,8 @@
   // If set, enable minidump for chrome crashes and save to this directory.
   std::string minidump_path;
 
-  std::string page_load_strategy;
-
-  std::string unexpected_alert_behaviour;
-
   bool network_emulation_enabled;
 
-  bool accept_insecure_certs;
-
   PerfLoggingPrefs perf_logging_prefs;
 
   std::unique_ptr<base::ListValue> devtools_events_logging_prefs;
diff --git a/chrome/test/chromedriver/session.h b/chrome/test/chromedriver/session.h
index 70bd049d..24ca85d 100644
--- a/chrome/test/chromedriver/session.h
+++ b/chrome/test/chromedriver/session.h
@@ -21,7 +21,9 @@
 #include "chrome/test/chromedriver/command_listener.h"
 
 static const char kAccept[] = "accept";
+static const char kAcceptAndNotify[] = "accept and notify";
 static const char kDismiss[] = "dismiss";
+static const char kDismissAndNotify[] = "dismiss and notify";
 static const char kIgnore[] = "ignore";
 
 // Controls whether ChromeDriver operates in W3C mode (when true) or legacy
@@ -104,7 +106,7 @@
   // |CommandListener|s might be |CommandListenerProxy|s that forward to
   // |DevToolsEventListener|s owned by |chrome|.
   std::vector<std::unique_ptr<CommandListener>> command_listeners;
-  std::string unexpected_alert_behaviour;
+  std::string unhandled_prompt_behavior;
 };
 
 Session* GetThreadLocalSession();
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 14e31f7c..3664417 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -134,8 +134,9 @@
   caps->SetBoolean("acceptInsecureCerts", capabilities.accept_insecure_certs);
   caps->SetBoolean("nativeEvents", true);
   caps->SetBoolean("hasTouchScreen", session->chrome->HasTouchScreen());
-  caps->SetString("unexpectedAlertBehaviour",
-                  session->unexpected_alert_behaviour);
+  caps->SetString(session->w3c_compliant ? "unhandledPromptBehavior"
+                                         : "unexpectedAlertBehaviour",
+                  session->unhandled_prompt_behavior);
 
   // add setWindowRect based on whether we are desktop/android/remote
   if (capabilities.IsAndroid() || capabilities.IsRemoteBrowser()) {
@@ -262,9 +263,11 @@
   Status status = capabilities.Parse(*desired_caps);
   if (status.IsError())
     return status;
+  status = capabilities.CheckSupport();
+  if (status.IsError())
+    return status;
 
-  desired_caps->GetString("unexpectedAlertBehaviour",
-                           &session->unexpected_alert_behaviour);
+  session->unhandled_prompt_behavior = capabilities.unhandled_prompt_behavior;
 
   Log::Level driver_level = Log::kWarning;
   if (capabilities.logging_prefs.count(WebDriverLog::kDriverType))
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index 766a01a4..f7360859 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -249,10 +249,10 @@
 
     // Close the dialog depending on the unexpectedalert behaviour set by user
     // before returning an error, so that subsequent commands do not fail.
-    std::string alert_behaviour = session->unexpected_alert_behaviour;
-    if (alert_behaviour == kAccept)
+    std::string prompt_behavior = session->unhandled_prompt_behavior;
+    if (prompt_behavior == kAccept)
       status = dialog_manager->HandleDialog(true, session->prompt_text.get());
-    else if (alert_behaviour == kDismiss)
+    else if (prompt_behavior == kDismiss)
       status = dialog_manager->HandleDialog(false, session->prompt_text.get());
     if (status.IsError())
       return status;
diff --git a/chrome/test/data/emptybeforeunload.html b/chrome/test/data/emptybeforeunload.html
new file mode 100644
index 0000000..804efef
--- /dev/null
+++ b/chrome/test/data/emptybeforeunload.html
@@ -0,0 +1,11 @@
+<html>
+  <head>
+    <title>Loading...</title>
+    <script>
+      window.onbeforeunload = function(e) { return null; };
+    </script>
+  </head>
+  <body>
+    <p>Navigate to another page to trigger beforeunload handler.</p>
+  </body>
+</html>
diff --git a/chrome/test/data/extensions/api_test/debugger/background.js b/chrome/test/data/extensions/api_test/debugger/background.js
index ca2423d..3cbd7cb6 100644
--- a/chrome/test/data/extensions/api_test/debugger/background.js
+++ b/chrome/test/data/extensions/api_test/debugger/background.js
@@ -302,13 +302,24 @@
     const url = 'http://127.0.0.1//extensions/api_test/debugger/inspected.html';
     chrome.tabs.create({url: url}, function(tab) {
       var debuggee = {tabId: tab.id};
-      var failed = false;
+      var finished = false;
+      var failure = '';
+      var expectingFrameNavigated = false;
+
+      function finishIfError() {
+        if (chrome.runtime.lastError) {
+          failure = chrome.runtime.lastError.message;
+          finish(true);
+          return true;
+        }
+        return false;
+      }
 
       function onAttach() {
         chrome.debugger.sendCommand(debuggee, 'Network.enable', null,
-            () => chrome.test.assertNoLastError());
+            finishIfError);
         chrome.debugger.sendCommand(debuggee, 'Page.enable', null,
-            () => chrome.test.assertNoLastError());
+            finishIfError);
         var offlineParams = { offline: true, latency: 0,
             downloadThroughput: 0, uploadThroughput: 0 };
         chrome.debugger.sendCommand(debuggee,
@@ -317,31 +328,50 @@
       }
 
       function onOffline() {
-        chrome.test.assertNoLastError();
+        if (finishIfError())
+          return;
+        expectingFrameNavigated = true;
         chrome.debugger.sendCommand(debuggee, 'Page.reload', null,
-            () => chrome.test.assertNoLastError());
+            finishIfError);
       }
 
-      function cleanup(detach) {
+      function finish(detach) {
+        if (finished)
+          return;
+        finished = true;
         chrome.debugger.onDetach.removeListener(onDetach);
         chrome.debugger.onEvent.removeListener(onEvent);
         if (detach)
           chrome.debugger.detach(debuggee);
-        chrome.tabs.remove(tab.id);
+        chrome.tabs.remove(tab.id, () => {
+          if (failure)
+            chrome.test.fail(failure);
+          else
+            chrome.test.succeed();
+        });
       }
 
       function onDetach() {
-        failed = true;
-        cleanup(false);
-        chrome.test.fail('Detached before navigated to error page');
+        failure = 'Detached before navigated to error page';
+        finish(false);
       }
 
       function onEvent(_, method, params) {
-        if (failed || method !== 'Page.frameNavigated')
+        if (!expectingFrameNavigated || method !== 'Page.frameNavigated')
           return;
-        cleanup(true);
-        chrome.test.assertNoLastError();
-        chrome.test.succeed();
+
+        if (finishIfError())
+          return;
+
+        expectingFrameNavigated = false;
+        chrome.debugger.sendCommand(
+            debuggee, 'Page.navigate', {url: 'about:blank'}, onNavigateDone);
+      }
+
+      function onNavigateDone() {
+        if (finishIfError())
+          return;
+        finish(true);
       }
 
       chrome.debugger.onDetach.addListener(onDetach);
diff --git a/chrome/test/data/webui/print_preview/pages_settings_test.js b/chrome/test/data/webui/print_preview/pages_settings_test.js
index 9cb3c55..954fdc7 100644
--- a/chrome/test/data/webui/print_preview/pages_settings_test.js
+++ b/chrome/test/data/webui/print_preview/pages_settings_test.js
@@ -174,6 +174,10 @@
           })
           .then(function() {
             validateErrorState(syntaxError);
+            return setupInput('--', 100);
+          })
+          .then(function() {
+            validateErrorState(syntaxError);
           });
     });
 
diff --git a/chrome/test/data/webui/settings/sync_account_control_test.js b/chrome/test/data/webui/settings/sync_account_control_test.js
index 43675de..1f246a0 100644
--- a/chrome/test/data/webui/settings/sync_account_control_test.js
+++ b/chrome/test/data/webui/settings/sync_account_control_test.js
@@ -93,7 +93,12 @@
 
       assertVisible(testElement.$$('#promo-header'), true);
       assertVisible(testElement.$$('#avatar-row'), false);
-      assertVisible(testElement.$$('#menu'), false);
+      // TODO (rbpotter): Remove this conditional when the migration to
+      // Polymer 2 is completed.
+      if (Polymer.DomIf)
+        assertEquals(null, testElement.$$('#menu'));
+      else
+        assertVisible(testElement.$$('#menu'), false);
       assertVisible(testElement.$$('#sign-in'), true);
 
       testElement.$$('#sign-in').click();
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index 27853a3..2aaa2e8 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -57,6 +57,7 @@
     "autofill_manager.cc",
     "autofill_manager.h",
     "autofill_manager_test_delegate.h",
+    "autofill_metadata.h",
     "autofill_metrics.cc",
     "autofill_metrics.h",
     "autofill_popup_delegate.h",
diff --git a/components/autofill/core/browser/autofill_data_model.cc b/components/autofill/core/browser/autofill_data_model.cc
index 1d36be4..72464e8e 100644
--- a/components/autofill/core/browser/autofill_data_model.cc
+++ b/components/autofill/core/browser/autofill_data_model.cc
@@ -6,6 +6,7 @@
 
 #include <math.h>
 
+#include "components/autofill/core/browser/autofill_metadata.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/common/autofill_clock.h"
 #include "url/gurl.h"
@@ -46,6 +47,19 @@
   return guid_ > other->guid_;
 }
 
+AutofillMetadata AutofillDataModel::GetMetadata() const {
+  AutofillMetadata metadata;
+  metadata.use_count = use_count_;
+  metadata.use_date = use_date_;
+  return metadata;
+}
+
+bool AutofillDataModel::SetMetadata(const AutofillMetadata metadata) {
+  use_count_ = metadata.use_count;
+  use_date_ = metadata.use_date;
+  return true;
+}
+
 double AutofillDataModel::GetFrecencyScore(base::Time time) const {
   // The formula calculates a score based on both the frequency and the recency
   // of the profile and leveraging the properties of the logarithmic function.
diff --git a/components/autofill/core/browser/autofill_data_model.h b/components/autofill/core/browser/autofill_data_model.h
index 4cc373b..a9f562a 100644
--- a/components/autofill/core/browser/autofill_data_model.h
+++ b/components/autofill/core/browser/autofill_data_model.h
@@ -15,6 +15,8 @@
 
 namespace autofill {
 
+struct AutofillMetadata;
+
 // This class is an interface for the primary data models that back Autofill.
 // The information in objects of this class is managed by the
 // PersonalDataManager.
@@ -52,6 +54,13 @@
   bool CompareFrecency(const AutofillDataModel* other,
                        base::Time comparison_time) const;
 
+  // Gets the metadata associated with this autofill data model.
+  virtual AutofillMetadata GetMetadata() const;
+
+  // Sets the |use_count_| and |use_date_| of this autofill data model. Returns
+  // whether the metadata was set.
+  virtual bool SetMetadata(const AutofillMetadata metadata);
+
  protected:
   // Called to update |use_count_| and |use_date_| when this data model is
   // the subject of user interaction (usually, when it's used to fill a form).
diff --git a/components/autofill/core/browser/autofill_data_model_unittest.cc b/components/autofill/core/browser/autofill_data_model_unittest.cc
index 8432b10..5ab0d1b 100644
--- a/components/autofill/core/browser/autofill_data_model_unittest.cc
+++ b/components/autofill/core/browser/autofill_data_model_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/time/time.h"
+#include "components/autofill/core/browser/autofill_metadata.h"
 #include "components/autofill/core/common/autofill_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -16,6 +17,8 @@
 
 namespace {
 
+const base::Time kArbitraryTime = base::Time::FromDoubleT(25);
+
 // Provides concrete implementations for pure virtual methods.
 class TestAutofillDataModel : public AutofillDataModel {
  public:
@@ -71,6 +74,27 @@
   EXPECT_FALSE(model.IsVerified());
 }
 
+TEST(AutofillDataModelTest, GetMetadata) {
+  TestAutofillDataModel model("guid", std::string());
+  model.set_use_count(10);
+  model.set_use_date(kArbitraryTime);
+
+  AutofillMetadata metadata = model.GetMetadata();
+  EXPECT_EQ(model.use_count(), metadata.use_count);
+  EXPECT_EQ(model.use_date(), metadata.use_date);
+}
+
+TEST(AutofillDataModelTest, SetMetadata) {
+  AutofillMetadata metadata;
+  metadata.use_count = 10;
+  metadata.use_date = kArbitraryTime;
+
+  TestAutofillDataModel model("guid", std::string());
+  EXPECT_TRUE(model.SetMetadata(metadata));
+  EXPECT_EQ(metadata.use_count, model.use_count());
+  EXPECT_EQ(metadata.use_date, model.use_date());
+}
+
 enum Expectation { GREATER, LESS };
 struct CompareFrecencyTestCase {
   const std::string guid_a;
diff --git a/components/autofill/core/browser/autofill_metadata.h b/components/autofill/core/browser/autofill_metadata.h
new file mode 100644
index 0000000..ebaeb22
--- /dev/null
+++ b/components/autofill/core/browser/autofill_metadata.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 COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_METADATA_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_METADATA_H_
+
+#include <string>
+
+#include "base/time/time.h"
+
+namespace autofill {
+
+// This struct contains the metadata to an autofill data model. It is used to
+// abstract the data from the metadata.
+struct AutofillMetadata {
+ public:
+  AutofillMetadata(){};
+  ~AutofillMetadata(){};
+
+  // The ID for the model. This should be the guid for local data and server_id
+  // for the server data.
+  std::string id;
+
+  // The number of times the model has been used.
+  size_t use_count;
+
+  // The last time the model was used.
+  base::Time use_date;
+
+  // Only useful for SERVER_PROFILEs. Whether the server profile has been
+  // converted to a local profile.
+  bool has_converted;
+
+  // Only useful for SERVER_CARDs. The identifier of the billing address for the
+  // card.
+  std::string billing_address_id;
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_AUTOFILL_METADATA_H_
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index da32d58a..ffe5996 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -26,6 +26,7 @@
 #include "components/autofill/core/browser/address_i18n.h"
 #include "components/autofill/core/browser/autofill_country.h"
 #include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_metadata.h"
 #include "components/autofill/core/browser/autofill_metrics.h"
 #include "components/autofill/core/browser/autofill_profile_comparator.h"
 #include "components/autofill/core/browser/autofill_type.h"
@@ -285,6 +286,25 @@
   return *this;
 }
 
+AutofillMetadata AutofillProfile::GetMetadata() const {
+  AutofillMetadata metadata = AutofillDataModel::GetMetadata();
+  metadata.id = (record_type_ == LOCAL_PROFILE ? guid() : server_id_);
+  metadata.has_converted = has_converted_;
+  return metadata;
+}
+
+bool AutofillProfile::SetMetadata(const AutofillMetadata metadata) {
+  // Make sure the ids matches.
+  if (metadata.id != (record_type_ == LOCAL_PROFILE ? guid() : server_id_))
+    return false;
+
+  if (!AutofillDataModel::SetMetadata(metadata))
+    return false;
+
+  has_converted_ = metadata.has_converted;
+  return true;
+}
+
 // TODO(crbug.com/589535): Disambiguate similar field types before uploading.
 void AutofillProfile::GetMatchingTypes(
     const base::string16& text,
diff --git a/components/autofill/core/browser/autofill_profile.h b/components/autofill/core/browser/autofill_profile.h
index d928d7f..482878a 100644
--- a/components/autofill/core/browser/autofill_profile.h
+++ b/components/autofill/core/browser/autofill_profile.h
@@ -25,6 +25,8 @@
 
 namespace autofill {
 
+struct AutofillMetadata;
+
 // A collection of FormGroups stored in a profile.  AutofillProfile also
 // implements the FormGroup interface so that owners of this object can request
 // form information from the profile, and the profile will delegate the request
@@ -73,6 +75,10 @@
 
   AutofillProfile& operator=(const AutofillProfile& profile);
 
+  // AutofillDataModel:
+  AutofillMetadata GetMetadata() const override;
+  bool SetMetadata(const AutofillMetadata metadata) override;
+
   // FormGroup:
   void GetMatchingTypes(const base::string16& text,
                         const std::string& app_locale,
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc
index 3e7053c03..75197d85 100644
--- a/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/browser/autofill_metadata.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/field_types.h"
@@ -1690,4 +1691,78 @@
                                      AutofillProfile::AutofillProfile::CLIENT));
 }
 
+TEST(AutofillProfileTest, GetMetadata) {
+  AutofillProfile local_profile = test::GetFullProfile();
+  local_profile.set_use_count(2);
+  local_profile.set_use_date(base::Time::FromDoubleT(25));
+  local_profile.set_has_converted(false);
+  AutofillMetadata local_metadata = local_profile.GetMetadata();
+  EXPECT_EQ(local_profile.guid(), local_metadata.id);
+  EXPECT_EQ(local_profile.has_converted(), local_metadata.has_converted);
+  EXPECT_EQ(local_profile.use_count(), local_metadata.use_count);
+  EXPECT_EQ(local_profile.use_date(), local_metadata.use_date);
+
+  AutofillProfile server_profile = test::GetServerProfile();
+  server_profile.set_use_count(10);
+  server_profile.set_use_date(base::Time::FromDoubleT(100));
+  server_profile.set_has_converted(true);
+  AutofillMetadata server_metadata = server_profile.GetMetadata();
+  EXPECT_EQ(server_profile.server_id(), server_metadata.id);
+  EXPECT_EQ(server_profile.has_converted(), server_metadata.has_converted);
+  EXPECT_EQ(server_profile.use_count(), server_metadata.use_count);
+  EXPECT_EQ(server_profile.use_date(), server_metadata.use_date);
+}
+
+TEST(AutofillProfileTest, SetMetadata_MatchingId) {
+  AutofillProfile local_profile = test::GetFullProfile();
+  AutofillMetadata local_metadata;
+  local_metadata.id = local_profile.guid();
+  local_metadata.use_count = 100;
+  local_metadata.use_date = base::Time::FromDoubleT(50);
+  local_metadata.has_converted = true;
+  EXPECT_TRUE(local_profile.SetMetadata(local_metadata));
+  EXPECT_EQ(local_metadata.id, local_profile.guid());
+  EXPECT_EQ(local_metadata.has_converted, local_profile.has_converted());
+  EXPECT_EQ(local_metadata.use_count, local_profile.use_count());
+  EXPECT_EQ(local_metadata.use_date, local_profile.use_date());
+
+  AutofillProfile server_profile = test::GetServerProfile();
+  AutofillMetadata server_metadata;
+  server_metadata.id = server_profile.server_id();
+  server_metadata.use_count = 100;
+  server_metadata.use_date = base::Time::FromDoubleT(50);
+  server_metadata.has_converted = true;
+  EXPECT_TRUE(server_profile.SetMetadata(server_metadata));
+  EXPECT_EQ(server_metadata.id, server_profile.server_id());
+  EXPECT_EQ(server_metadata.has_converted, server_profile.has_converted());
+  EXPECT_EQ(server_metadata.use_count, server_profile.use_count());
+  EXPECT_EQ(server_metadata.use_date, server_profile.use_date());
+}
+
+TEST(AutofillProfileTest, SetMetadata_NotMatchingId) {
+  AutofillProfile local_profile = test::GetFullProfile();
+  AutofillMetadata local_metadata;
+  local_metadata.id = "WrongId";
+  local_metadata.use_count = 100;
+  local_metadata.use_date = base::Time::FromDoubleT(50);
+  local_metadata.has_converted = true;
+  EXPECT_FALSE(local_profile.SetMetadata(local_metadata));
+  EXPECT_NE(local_metadata.id, local_profile.guid());
+  EXPECT_NE(local_metadata.has_converted, local_profile.has_converted());
+  EXPECT_NE(local_metadata.use_count, local_profile.use_count());
+  EXPECT_NE(local_metadata.use_date, local_profile.use_date());
+
+  AutofillProfile server_profile = test::GetServerProfile();
+  AutofillMetadata server_metadata;
+  server_metadata.id = "WrongId";
+  server_metadata.use_count = 100;
+  server_metadata.use_date = base::Time::FromDoubleT(50);
+  server_metadata.has_converted = true;
+  EXPECT_FALSE(server_profile.SetMetadata(server_metadata));
+  EXPECT_NE(server_metadata.id, server_profile.guid());
+  EXPECT_NE(server_metadata.has_converted, server_profile.has_converted());
+  EXPECT_NE(server_metadata.use_count, server_profile.use_count());
+  EXPECT_NE(server_metadata.use_date, server_profile.use_date());
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc
index f5df5df..325c2db 100644
--- a/components/autofill/core/browser/autofill_test_utils.cc
+++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -428,6 +428,14 @@
   return credit_card;
 }
 
+CreditCard GetFullServerCard() {
+  CreditCard credit_card(CreditCard::FULL_SERVER_CARD, "c123");
+  test::SetCreditCardInfo(&credit_card, "Full Carter",
+                          "4111111111111111" /* Visa */, "12", "2020", "1");
+  credit_card.set_card_type(CreditCard::CARD_TYPE_CREDIT);
+  return credit_card;
+}
+
 CreditCard GetRandomCreditCard(CreditCard::RecordType record_type) {
   static const char* const kNetworks[] = {
       kAmericanExpressCard,
diff --git a/components/autofill/core/browser/autofill_test_utils.h b/components/autofill/core/browser/autofill_test_utils.h
index 0817dcbd8..2e7aebd 100644
--- a/components/autofill/core/browser/autofill_test_utils.h
+++ b/components/autofill/core/browser/autofill_test_utils.h
@@ -137,6 +137,9 @@
 CreditCard GetMaskedServerCard();
 CreditCard GetMaskedServerCardAmex();
 
+// Returns a full server card full of dummy info.
+CreditCard GetFullServerCard();
+
 // Returns a randomly generated credit card of |record_type|. Note that the
 // card is not guaranteed to be valid/sane from a card validation standpoint.
 CreditCard GetRandomCreditCard(CreditCard::RecordType record_Type);
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index 3c309e8b..0a4a2894 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -29,6 +29,7 @@
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_data_util.h"
 #include "components/autofill/core/browser/autofill_field.h"
+#include "components/autofill/core/browser/autofill_metadata.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_clock.h"
@@ -312,6 +313,25 @@
   return server_status_;
 }
 
+AutofillMetadata CreditCard::GetMetadata() const {
+  AutofillMetadata metadata = AutofillDataModel::GetMetadata();
+  metadata.id = (record_type_ == LOCAL_CARD ? guid() : server_id_);
+  metadata.billing_address_id = billing_address_id_;
+  return metadata;
+}
+
+bool CreditCard::SetMetadata(const AutofillMetadata metadata) {
+  // Make sure the ids matches.
+  if (metadata.id != (record_type_ == LOCAL_CARD ? guid() : server_id_))
+    return false;
+
+  if (!AutofillDataModel::SetMetadata(metadata))
+    return false;
+
+  billing_address_id_ = metadata.billing_address_id;
+  return true;
+}
+
 base::string16 CreditCard::GetRawInfo(ServerFieldType type) const {
   DCHECK_EQ(CREDIT_CARD, AutofillType(type).group());
   switch (type) {
diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h
index 9fa815d..815d788 100644
--- a/components/autofill/core/browser/credit_card.h
+++ b/components/autofill/core/browser/credit_card.h
@@ -19,6 +19,8 @@
 
 namespace autofill {
 
+struct AutofillMetadata;
+
 // A midline horizontal ellipsis (U+22EF).
 extern const base::char16 kMidlineEllipsis[];
 
@@ -106,6 +108,10 @@
   void SetServerStatus(ServerStatus status);
   ServerStatus GetServerStatus() const;
 
+  // AutofillDataModel:
+  AutofillMetadata GetMetadata() const override;
+  bool SetMetadata(const AutofillMetadata metadata) override;
+
   // FormGroup:
   void GetMatchingTypes(const base::string16& text,
                         const std::string& app_locale,
diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc
index 05f85fe4..88a452f 100644
--- a/components/autofill/core/browser/credit_card_unittest.cc
+++ b/components/autofill/core/browser/credit_card_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "components/autofill/core/browser/autofill_experiments.h"
+#include "components/autofill/core/browser/autofill_metadata.h"
 #include "components/autofill/core/browser/autofill_test_utils.h"
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/credit_card.h"
@@ -233,6 +234,117 @@
   EXPECT_EQ(a, b);
 }
 
+TEST(CreditCardTest, GetMetadata) {
+  CreditCard local_card = test::GetCreditCard();
+  local_card.set_use_count(2);
+  local_card.set_use_date(base::Time::FromDoubleT(25));
+  local_card.set_billing_address_id("123");
+  AutofillMetadata local_metadata = local_card.GetMetadata();
+  EXPECT_EQ(local_card.guid(), local_metadata.id);
+  EXPECT_EQ(local_card.billing_address_id(), local_metadata.billing_address_id);
+  EXPECT_EQ(local_card.use_count(), local_metadata.use_count);
+  EXPECT_EQ(local_card.use_date(), local_metadata.use_date);
+
+  CreditCard masked_card = test::GetMaskedServerCard();
+  masked_card.set_use_count(4);
+  masked_card.set_use_date(base::Time::FromDoubleT(50));
+  masked_card.set_billing_address_id("abc");
+  AutofillMetadata masked_metadata = masked_card.GetMetadata();
+  EXPECT_EQ(masked_card.server_id(), masked_metadata.id);
+  EXPECT_EQ(masked_card.billing_address_id(),
+            masked_metadata.billing_address_id);
+  EXPECT_EQ(masked_card.use_count(), masked_metadata.use_count);
+  EXPECT_EQ(masked_card.use_date(), masked_metadata.use_date);
+
+  CreditCard full_card = test::GetFullServerCard();
+  full_card.set_use_count(6);
+  full_card.set_use_date(base::Time::FromDoubleT(100));
+  full_card.set_billing_address_id("xyz");
+  AutofillMetadata full_metadata = full_card.GetMetadata();
+  EXPECT_EQ(full_card.server_id(), full_metadata.id);
+  EXPECT_EQ(full_card.billing_address_id(), full_metadata.billing_address_id);
+  EXPECT_EQ(full_card.use_count(), full_metadata.use_count);
+  EXPECT_EQ(full_card.use_date(), full_metadata.use_date);
+}
+
+TEST(CreditCardTest, SetMetadata_MatchingId) {
+  CreditCard local_card = test::GetCreditCard();
+  AutofillMetadata local_metadata;
+  local_metadata.id = local_card.guid();
+  local_metadata.use_count = 100;
+  local_metadata.use_date = base::Time::FromDoubleT(50);
+  local_metadata.billing_address_id = "billId1";
+  EXPECT_TRUE(local_card.SetMetadata(local_metadata));
+  EXPECT_EQ(local_metadata.id, local_card.guid());
+  EXPECT_EQ(local_metadata.billing_address_id, local_card.billing_address_id());
+  EXPECT_EQ(local_metadata.use_count, local_card.use_count());
+  EXPECT_EQ(local_metadata.use_date, local_card.use_date());
+
+  CreditCard masked_card = test::GetMaskedServerCard();
+  AutofillMetadata masked_metadata;
+  masked_metadata.id = masked_card.server_id();
+  masked_metadata.use_count = 100;
+  masked_metadata.use_date = base::Time::FromDoubleT(50);
+  masked_metadata.billing_address_id = "billId1";
+  EXPECT_TRUE(masked_card.SetMetadata(masked_metadata));
+  EXPECT_EQ(masked_metadata.id, masked_card.server_id());
+  EXPECT_EQ(masked_metadata.billing_address_id,
+            masked_card.billing_address_id());
+  EXPECT_EQ(masked_metadata.use_count, masked_card.use_count());
+  EXPECT_EQ(masked_metadata.use_date, masked_card.use_date());
+
+  CreditCard full_card = test::GetFullServerCard();
+  AutofillMetadata full_metadata;
+  full_metadata.id = full_card.server_id();
+  full_metadata.use_count = 100;
+  full_metadata.use_date = base::Time::FromDoubleT(50);
+  full_metadata.billing_address_id = "billId1";
+  EXPECT_TRUE(full_card.SetMetadata(full_metadata));
+  EXPECT_EQ(full_metadata.id, full_card.server_id());
+  EXPECT_EQ(full_metadata.billing_address_id, full_card.billing_address_id());
+  EXPECT_EQ(full_metadata.use_count, full_card.use_count());
+  EXPECT_EQ(full_metadata.use_date, full_card.use_date());
+}
+
+TEST(CreditCardTest, SetMetadata_NotMatchingId) {
+  CreditCard local_card = test::GetCreditCard();
+  AutofillMetadata local_metadata;
+  local_metadata.id = "WrongId";
+  local_metadata.use_count = 100;
+  local_metadata.use_date = base::Time::FromDoubleT(50);
+  local_metadata.billing_address_id = "billId1";
+  EXPECT_FALSE(local_card.SetMetadata(local_metadata));
+  EXPECT_NE(local_metadata.id, local_card.guid());
+  EXPECT_NE(local_metadata.billing_address_id, local_card.billing_address_id());
+  EXPECT_NE(local_metadata.use_count, local_card.use_count());
+  EXPECT_NE(local_metadata.use_date, local_card.use_date());
+
+  CreditCard masked_card = test::GetMaskedServerCard();
+  AutofillMetadata masked_metadata;
+  masked_metadata.id = "WrongId";
+  masked_metadata.use_count = 100;
+  masked_metadata.use_date = base::Time::FromDoubleT(50);
+  masked_metadata.billing_address_id = "billId1";
+  EXPECT_FALSE(masked_card.SetMetadata(masked_metadata));
+  EXPECT_NE(masked_metadata.id, masked_card.server_id());
+  EXPECT_NE(masked_metadata.billing_address_id,
+            masked_card.billing_address_id());
+  EXPECT_NE(masked_metadata.use_count, masked_card.use_count());
+  EXPECT_NE(masked_metadata.use_date, masked_card.use_date());
+
+  CreditCard full_card = test::GetFullServerCard();
+  AutofillMetadata full_metadata;
+  full_metadata.id = "WrongId";
+  full_metadata.use_count = 100;
+  full_metadata.use_date = base::Time::FromDoubleT(50);
+  full_metadata.billing_address_id = "billId1";
+  EXPECT_FALSE(full_card.SetMetadata(full_metadata));
+  EXPECT_NE(full_metadata.id, full_card.server_id());
+  EXPECT_NE(full_metadata.billing_address_id, full_card.billing_address_id());
+  EXPECT_NE(full_metadata.use_count, full_card.use_count());
+  EXPECT_NE(full_metadata.use_date, full_card.use_date());
+}
+
 struct SetExpirationYearFromStringTestCase {
   std::string expiration_year;
   int expected_year;
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h
index 53eea81..236b28d 100644
--- a/components/autofill_assistant/browser/actions/action_delegate.h
+++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -67,13 +67,11 @@
   virtual void FocusElement(const std::vector<std::string>& selectors,
                             base::OnceCallback<void(bool)> callback) = 0;
 
-  // Get the value of all fields in |selector_list| and return the result
-  // through |callback|. The list of returned values will have the same size as
-  // |selectors_list|, and will be the empty string in case of error or empty
-  // value.
-  virtual void GetFieldsValue(
-      const std::vector<std::vector<std::string>>& selectors_list,
-      base::OnceCallback<void(const std::vector<std::string>&)> callback) = 0;
+  // Get the value of |selectors| and return the result through |callback|. The
+  // returned value will be the empty string in case of error or empty value.
+  virtual void GetFieldValue(
+      const std::vector<std::string>& selectors,
+      base::OnceCallback<void(const std::string&)> callback) = 0;
 
   // Set the |values| of all fields in |selectors_list| and return the result
   // through |callback|. Selectors and values are one on one matched, i.e. the
diff --git a/components/autofill_assistant/browser/actions/autofill_action.cc b/components/autofill_assistant/browser/actions/autofill_action.cc
index 3df90c8..4451e7ae 100644
--- a/components/autofill_assistant/browser/actions/autofill_action.cc
+++ b/components/autofill_assistant/browser/actions/autofill_action.cc
@@ -175,33 +175,42 @@
     return;
   }
 
-  std::vector<std::vector<std::string>> selectors_list;
-  for (const auto& required_address_field :
-       proto_.use_address().required_fields()) {
-    selectors_list.emplace_back(std::vector<std::string>());
+  int required_fields_size = proto_.use_address().required_fields_size();
+  required_fields_value_status_.clear();
+  required_fields_value_status_.resize(required_fields_size, UNKNOWN);
+  for (int i = 0; i < required_fields_size; i++) {
+    const auto& required_address_field =
+        proto_.use_address().required_fields(i);
     DCHECK(required_address_field.has_address_field());
     DCHECK(!required_address_field.element().selectors().empty());
+    std::vector<std::string> selectors;
     for (const auto& selector : required_address_field.element().selectors()) {
-      selectors_list.back().emplace_back(selector);
+      selectors.emplace_back(selector);
     }
+    delegate->GetFieldValue(
+        selectors,
+        base::BindOnce(&AutofillAction::OnGetRequiredFieldValue,
+                       weak_ptr_factory_.GetWeakPtr(), guid, delegate,
+                       std::move(action_callback), allow_fallback, i));
   }
-
-  delegate->GetFieldsValue(
-      selectors_list,
-      base::BindOnce(&AutofillAction::OnGetRequiredFieldsValue,
-                     weak_ptr_factory_.GetWeakPtr(), guid, delegate,
-                     std::move(action_callback), allow_fallback));
 }
 
-void AutofillAction::OnGetRequiredFieldsValue(
+void AutofillAction::OnGetRequiredFieldValue(
     const std::string& guid,
     ActionDelegate* delegate,
     ProcessActionCallback action_callback,
     bool allow_fallback,
-    const std::vector<std::string>& values) {
+    int index,
+    const std::string& value) {
   DCHECK(!is_autofill_card_);
-  DCHECK_EQ(proto_.use_address().required_fields_size(),
-            static_cast<int>(values.size()));
+  required_fields_value_status_[index] = value.empty() ? EMPTY : NOT_EMPTY;
+
+  // Wait for the value of all required fields.
+  for (const auto& status : required_fields_value_status_) {
+    if (status == UNKNOWN) {
+      return;
+    }
+  }
 
   const autofill::AutofillProfile* profile = delegate->GetAutofillProfile(guid);
   DCHECK(profile);
@@ -211,8 +220,8 @@
   bool validation_successful = true;
   std::vector<std::vector<std::string>> failed_selectors;
   std::vector<std::string> fallback_values;
-  for (size_t i = 0; i < values.size(); i++) {
-    if (values[i].empty()) {
+  for (size_t i = 0; i < required_fields_value_status_.size(); i++) {
+    if (required_fields_value_status_[i] == EMPTY) {
       if (!allow_fallback) {
         // Validation failed and we don't want to try the fallback, so we fail
         // the action.
diff --git a/components/autofill_assistant/browser/actions/autofill_action.h b/components/autofill_assistant/browser/actions/autofill_action.h
index bee8523..4218f08 100644
--- a/components/autofill_assistant/browser/actions/autofill_action.h
+++ b/components/autofill_assistant/browser/actions/autofill_action.h
@@ -30,6 +30,8 @@
                      ProcessActionCallback callback) override;
 
  private:
+  enum FieldValueStatus { UNKNOWN, EMPTY, NOT_EMPTY };
+
   // Called when the user selected the data.
   void OnDataSelected(ActionDelegate* delegate,
                       ProcessActionCallback callback,
@@ -57,11 +59,12 @@
                            bool allow_fallback);
 
   // Called when we get the value of the required fields.
-  void OnGetRequiredFieldsValue(const std::string& guid,
-                                ActionDelegate* delegate,
-                                ProcessActionCallback action_callback,
-                                bool allow_fallback,
-                                const std::vector<std::string>& values);
+  void OnGetRequiredFieldValue(const std::string& guid,
+                               ActionDelegate* delegate,
+                               ProcessActionCallback action_callback,
+                               bool allow_fallback,
+                               int index,
+                               const std::string& value);
 
   // Get the value of |address_field| associated to profile |profile|. Return
   // empty string if there is no data available.
@@ -83,6 +86,7 @@
 
   // True if autofilling a card, otherwise we are autofilling an address.
   bool is_autofill_card_;
+  std::vector<FieldValueStatus> required_fields_value_status_;
   base::WeakPtrFactory<AutofillAction> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AutofillAction);
diff --git a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
index 0b9edceb..5aae1bd 100644
--- a/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
+++ b/components/autofill_assistant/browser/actions/wait_for_dom_action.cc
@@ -58,14 +58,7 @@
                                             int rounds,
                                             ProcessActionCallback callback,
                                             bool result) {
-  bool for_absence = proto_.wait_for_dom().check_for_absence();
-  if (for_absence && !result) {
-    UpdateProcessedAction(true);
-    std::move(callback).Run(std::move(processed_action_proto_));
-    return;
-  }
-
-  if (!for_absence && result) {
+  if (result) {
     UpdateProcessedAction(true);
     std::move(callback).Run(std::move(processed_action_proto_));
     return;
diff --git a/components/autofill_assistant/browser/mock_web_controller.h b/components/autofill_assistant/browser/mock_web_controller.h
index 3a70c39..c243260 100644
--- a/components/autofill_assistant/browser/mock_web_controller.h
+++ b/components/autofill_assistant/browser/mock_web_controller.h
@@ -38,6 +38,15 @@
   MOCK_METHOD2(OnElementExists,
                void(const std::vector<std::string>& selectors,
                     base::OnceCallback<void(bool)>& callback));
+
+  void GetFieldValue(
+      const std::vector<std::string>& selectors,
+      base::OnceCallback<void(const std::string&)> callback) override {
+    OnGetFieldValue(selectors, callback);
+  }
+  MOCK_METHOD2(OnGetFieldValue,
+               void(const std::vector<std::string>& selectors,
+                    base::OnceCallback<void(const std::string&)>& callback));
 };
 
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc
index 59f4ef41..d7f3379 100644
--- a/components/autofill_assistant/browser/script_executor.cc
+++ b/components/autofill_assistant/browser/script_executor.cc
@@ -86,11 +86,10 @@
   delegate_->GetWebController()->FocusElement(selectors, std::move(callback));
 }
 
-void ScriptExecutor::GetFieldsValue(
-    const std::vector<std::vector<std::string>>& selectors_list,
-    base::OnceCallback<void(const std::vector<std::string>&)> callback) {
-  delegate_->GetWebController()->GetFieldsValue(selectors_list,
-                                                std::move(callback));
+void ScriptExecutor::GetFieldValue(
+    const std::vector<std::string>& selectors,
+    base::OnceCallback<void(const std::string&)> callback) {
+  delegate_->GetWebController()->GetFieldValue(selectors, std::move(callback));
 }
 
 void ScriptExecutor::SetFieldsValue(
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h
index 218f826f..fa9f1fb6 100644
--- a/components/autofill_assistant/browser/script_executor.h
+++ b/components/autofill_assistant/browser/script_executor.h
@@ -51,10 +51,9 @@
                     base::OnceCallback<void(bool)> callback) override;
   void FocusElement(const std::vector<std::string>& selectors,
                     base::OnceCallback<void(bool)> callback) override;
-  void GetFieldsValue(
-      const std::vector<std::vector<std::string>>& selectors_list,
-      base::OnceCallback<void(const std::vector<std::string>&)> callback)
-      override;
+  void GetFieldValue(
+      const std::vector<std::string>& selectors,
+      base::OnceCallback<void(const std::string&)> callback) override;
   void SetFieldsValue(
       const std::vector<std::vector<std::string>>& selectors_list,
       const std::vector<std::string>& values,
diff --git a/components/autofill_assistant/browser/script_precondition.cc b/components/autofill_assistant/browser/script_precondition.cc
index f632b43d..e324747 100644
--- a/components/autofill_assistant/browser/script_precondition.cc
+++ b/components/autofill_assistant/browser/script_precondition.cc
@@ -46,10 +46,16 @@
     parameter_match.emplace_back(match);
   }
 
+  std::vector<FormValueMatchProto> form_value_match;
+  for (const auto& match : proto.form_value_match()) {
+    form_value_match.emplace_back(match);
+  }
+
   // TODO(crbug.com/806868): Detect unknown or unsupported conditions and reject
   // them.
   return std::make_unique<ScriptPrecondition>(
-      elements_exist, domain_match, std::move(path_pattern), parameter_match);
+      elements_exist, domain_match, std::move(path_pattern), parameter_match,
+      form_value_match);
 }
 
 ScriptPrecondition::~ScriptPrecondition() {}
@@ -64,44 +70,60 @@
     return;
   }
 
-  if (elements_exist_.empty()) {
+  pending_preconditions_check_count_ =
+      elements_exist_.size() + form_value_match_.size();
+  if (!pending_preconditions_check_count_) {
     std::move(callback).Run(true);
     return;
   }
 
+  // TODO(crbug.com/806868): Instead of running all checks in parallel and
+  // waiting for all of them to be finished, it might be better to check them
+  // one by one and fail the precondition early when one fails.
   check_preconditions_callback_ = std::move(callback);
-  pending_elements_exist_check_ = 0;
+  all_preconditions_check_satisfied_ = true;
+
   for (const auto& element : elements_exist_) {
-    pending_elements_exist_check_++;
     web_controller->ElementExists(
         element, base::BindOnce(&ScriptPrecondition::OnCheckElementExists,
                                 weak_ptr_factory_.GetWeakPtr()));
   }
+
+  for (const auto& value_match : form_value_match_) {
+    DCHECK(!value_match.element().selectors().empty());
+    std::vector<std::string> selectors;
+    for (const auto& selector : value_match.element().selectors()) {
+      selectors.emplace_back(selector);
+    }
+    web_controller->GetFieldValue(
+        selectors, base::BindOnce(&ScriptPrecondition::OnGetFieldValue,
+                                  weak_ptr_factory_.GetWeakPtr()));
+  }
 }
 
 ScriptPrecondition::ScriptPrecondition(
     const std::vector<std::vector<std::string>>& elements_exist,
     const std::set<std::string>& domain_match,
     std::vector<std::unique_ptr<re2::RE2>> path_pattern,
-    const std::vector<ScriptParameterMatchProto>& parameter_match)
+    const std::vector<ScriptParameterMatchProto>& parameter_match,
+    const std::vector<FormValueMatchProto>& form_value_match)
     : elements_exist_(elements_exist),
+      pending_preconditions_check_count_(0),
+      all_preconditions_check_satisfied_(false),
       domain_match_(domain_match),
       path_pattern_(std::move(path_pattern)),
       parameter_match_(parameter_match),
+      form_value_match_(form_value_match),
       weak_ptr_factory_(this) {}
 
 void ScriptPrecondition::OnCheckElementExists(bool result) {
-  pending_elements_exist_check_--;
-  // Return false early if there is a check failed.
+  DCHECK_LT(0u, pending_preconditions_check_count_);
+  pending_preconditions_check_count_--;
   if (!result) {
-    std::move(check_preconditions_callback_).Run(false);
-    return;
+    all_preconditions_check_satisfied_ = false;
   }
 
-  // Return true if all checks have been completed and there is no failed check.
-  if (!pending_elements_exist_check_ && check_preconditions_callback_) {
-    std::move(check_preconditions_callback_).Run(true);
-  }
+  MaybeRunCheckPreconditionCallback();
 }
 
 bool ScriptPrecondition::MatchDomain(const GURL& url) const {
@@ -145,4 +167,22 @@
   }
   return true;
 }
+
+void ScriptPrecondition::OnGetFieldValue(const std::string& value) {
+  DCHECK_LT(0u, pending_preconditions_check_count_);
+  pending_preconditions_check_count_--;
+  if (value.empty()) {
+    all_preconditions_check_satisfied_ = false;
+  }
+
+  MaybeRunCheckPreconditionCallback();
+}
+
+void ScriptPrecondition::MaybeRunCheckPreconditionCallback() {
+  if (!pending_preconditions_check_count_ && check_preconditions_callback_) {
+    std::move(check_preconditions_callback_)
+        .Run(all_preconditions_check_satisfied_);
+  }
+}
+
 }  // namespace autofill_assistant.
diff --git a/components/autofill_assistant/browser/script_precondition.h b/components/autofill_assistant/browser/script_precondition.h
index 9bf9b37..210775f 100644
--- a/components/autofill_assistant/browser/script_precondition.h
+++ b/components/autofill_assistant/browser/script_precondition.h
@@ -35,7 +35,8 @@
       const std::vector<std::vector<std::string>>& elements_exist,
       const std::set<std::string>& domain_match,
       std::vector<std::unique_ptr<re2::RE2>> path_pattern,
-      const std::vector<ScriptParameterMatchProto>& parameter_match);
+      const std::vector<ScriptParameterMatchProto>& parameter_match,
+      const std::vector<FormValueMatchProto>& form_value_match);
   ~ScriptPrecondition();
 
   // Check whether the conditions satisfied and return the result through
@@ -50,10 +51,16 @@
   bool MatchPath(const GURL& url) const;
   bool MatchParameters(
       const std::map<std::string, std::string>& parameters) const;
+  void OnGetFieldValue(const std::string& value);
+
+  // Return if all checks have been completed and we have not returned anything
+  // yet.
+  void MaybeRunCheckPreconditionCallback();
 
   std::vector<std::vector<std::string>> elements_exist_;
   base::OnceCallback<void(bool)> check_preconditions_callback_;
-  size_t pending_elements_exist_check_;
+  size_t pending_preconditions_check_count_;
+  bool all_preconditions_check_satisfied_;
 
   // Domain (exact match) excluding the last '/' character.
   std::set<std::string> domain_match_;
@@ -64,6 +71,9 @@
   // Condition on parameters, identified by name, as found in the intent.
   std::vector<ScriptParameterMatchProto> parameter_match_;
 
+  // Conditions on form fields value.
+  std::vector<FormValueMatchProto> form_value_match_;
+
   base::WeakPtrFactory<ScriptPrecondition> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(ScriptPrecondition);
diff --git a/components/autofill_assistant/browser/script_precondition_unittest.cc b/components/autofill_assistant/browser/script_precondition_unittest.cc
index e19e119b..dfff053 100644
--- a/components/autofill_assistant/browser/script_precondition_unittest.cc
+++ b/components/autofill_assistant/browser/script_precondition_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/run_loop.h"
 #include "components/autofill_assistant/browser/mock_run_once_callback.h"
 #include "components/autofill_assistant/browser/mock_web_controller.h"
 #include "components/autofill_assistant/browser/service.pb.h"
@@ -61,6 +62,11 @@
     SetUrl("http://www.example.com/path");
     ON_CALL(mock_web_controller_, GetUrl())
         .WillByDefault(Invoke(this, &ScriptPreconditionTest::GetUrl));
+    ON_CALL(mock_web_controller_, OnGetFieldValue(ElementsAre("exists"), _))
+        .WillByDefault(RunOnceCallback<1>("foo"));
+    ON_CALL(mock_web_controller_,
+            OnGetFieldValue(ElementsAre("does_not_exist"), _))
+        .WillByDefault(RunOnceCallback<1>(""));
   }
 
  protected:
@@ -197,5 +203,15 @@
   EXPECT_FALSE(Check(proto));
 }
 
+TEST_F(ScriptPreconditionTest, FormValueMatch) {
+  ScriptPreconditionProto proto;
+  FormValueMatchProto* match = proto.add_form_value_match();
+  match->mutable_element()->add_selectors("exists");
+  EXPECT_TRUE(Check(proto));
+
+  match->mutable_element()->set_selectors(0, "does_not_exist");
+  EXPECT_FALSE(Check(proto));
+}
+
 }  // namespace
 }  // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/service.proto b/components/autofill_assistant/browser/service.proto
index 2cef1f6..671a3bb7 100644
--- a/components/autofill_assistant/browser/service.proto
+++ b/components/autofill_assistant/browser/service.proto
@@ -69,6 +69,8 @@
   repeated string domain = 6;
   // Combined with AND: all matches must be true for precondition to hold.
   repeated ScriptParameterMatchProto script_parameter_match = 7;
+  // Combined with AND: all matches must be true for precondition to hold.
+  repeated FormValueMatchProto form_value_match = 9;
 }
 
 message ScriptParameterMatchProto {
@@ -83,6 +85,12 @@
   optional string value_equals = 3;
 }
 
+message FormValueMatchProto {
+  // Required. The selector associated to the form element whose value should be
+  // checked.
+  optional ElementReferenceProto element = 1;
+}
+
 enum PolicyType {
   UNKNOWN_POLICY = 0;
   SCRIPT = 1;
@@ -302,10 +310,6 @@
 
   // Fail after waiting this amount of time.
   optional int32 timeout_ms = 2;
-
-  // If true, wait for the given element to be absent, otherwise wait for
-  // existence.
-  optional bool check_for_absence = 3;
 }
 
 // Volatile upload of a portion of the dom for backend analysis, does not store
diff --git a/components/autofill_assistant/browser/web_controller.cc b/components/autofill_assistant/browser/web_controller.cc
index d941614c..8c07096 100644
--- a/components/autofill_assistant/browser/web_controller.cc
+++ b/components/autofill_assistant/browser/web_controller.cc
@@ -54,6 +54,10 @@
       return true;
     })";
 
+// Javascript code to retrieve the 'value' attribute of a node.
+const char* const kGetValueAttributeScript =
+    "function () { return this.value; }";
+
 }  // namespace
 
 // static
@@ -390,6 +394,13 @@
   std::move(callback).Run(result);
 }
 
+void WebController::OnResult(
+    const std::string& result,
+    base::OnceCallback<void(const std::string&)> callback) {
+  devtools_client_->GetDOM()->Disable();
+  std::move(callback).Run(result);
+}
+
 void WebController::OnFindElementForFocusElement(
     base::OnceCallback<void(bool)> callback,
     std::unique_ptr<FindElementResult> element_result) {
@@ -574,15 +585,51 @@
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
 }
 
-void WebController::GetFieldsValue(
-    const std::vector<std::vector<std::string>>& selectors_list,
-    base::OnceCallback<void(const std::vector<std::string>&)> callback) {
-  // TODO(crbug.com/806868): Implement get fields value operation.
-  std::vector<std::string> values;
-  for (size_t i = 0; i < selectors_list.size(); i++) {
-    values.emplace_back("");
+void WebController::GetFieldValue(
+    const std::vector<std::string>& selectors,
+    base::OnceCallback<void(const std::string&)> callback) {
+  FindElement(
+      selectors,
+      base::BindOnce(&WebController::OnFindElementForGetFieldValue,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void WebController::OnFindElementForGetFieldValue(
+    base::OnceCallback<void(const std::string&)> callback,
+    std::unique_ptr<FindElementResult> element_result) {
+  const std::string object_id = element_result->object_id;
+  if (object_id.empty()) {
+    OnResult("", std::move(callback));
+    return;
   }
-  std::move(callback).Run(values);
+
+  std::vector<std::unique_ptr<runtime::CallArgument>> argument;
+  argument.emplace_back(
+      runtime::CallArgument::Builder().SetObjectId(object_id).Build());
+  devtools_client_->GetRuntime()->Enable();
+  devtools_client_->GetRuntime()->CallFunctionOn(
+      runtime::CallFunctionOnParams::Builder()
+          .SetObjectId(object_id)
+          .SetArguments(std::move(argument))
+          .SetFunctionDeclaration(std::string(kGetValueAttributeScript))
+          .SetReturnByValue(true)
+          .Build(),
+      base::BindOnce(&WebController::OnGetValueAttribute,
+                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void WebController::OnGetValueAttribute(
+    base::OnceCallback<void(const std::string&)> callback,
+    std::unique_ptr<runtime::CallFunctionOnResult> result) {
+  devtools_client_->GetRuntime()->Disable();
+  if (!result || result->HasExceptionDetails()) {
+    OnResult("", std::move(callback));
+    return;
+  }
+
+  // Read the result returned from Javascript code.
+  DCHECK(result->GetResult()->GetValue()->is_string());
+  OnResult(result->GetResult()->GetValue()->GetString(), std::move(callback));
 }
 
 void WebController::SetFieldsValue(
diff --git a/components/autofill_assistant/browser/web_controller.h b/components/autofill_assistant/browser/web_controller.h
index 6d58b52..1e57e87e 100644
--- a/components/autofill_assistant/browser/web_controller.h
+++ b/components/autofill_assistant/browser/web_controller.h
@@ -78,13 +78,11 @@
   virtual void FocusElement(const std::vector<std::string>& selectors,
                             base::OnceCallback<void(bool)> callback);
 
-  // Get the value of all fields in |selector_list| and return the result
-  // through |callback|. The list of returned values will have the same size as
-  // |selectors_list|, and will be the empty string in case of error or empty
-  // value.
-  virtual void GetFieldsValue(
-      const std::vector<std::vector<std::string>>& selectors_list,
-      base::OnceCallback<void(const std::vector<std::string>&)> callback);
+  // Get the value of |selectors| and return the result through |callback|. The
+  // returned value will be the empty string in case of error or empty value.
+  virtual void GetFieldValue(
+      const std::vector<std::string>& selectors,
+      base::OnceCallback<void(const std::string&)> callback);
 
   // Set the |values| of all fields in |selectors_list| and return the result
   // through |callback|. Selectors and values are one on one matched, i.e. the
@@ -176,6 +174,8 @@
       FindElementCallback callback,
       std::unique_ptr<dom::PushNodesByBackendIdsToFrontendResult> result);
   void OnResult(bool result, base::OnceCallback<void(bool)> callback);
+  void OnResult(const std::string& result,
+                base::OnceCallback<void(const std::string&)> callback);
   void OnFindElementForFillingForm(
       const std::string& autofill_data_guid,
       const std::vector<std::string>& selectors,
@@ -204,6 +204,12 @@
       std::unique_ptr<FindElementResult> element_result);
   void OnSelectOption(base::OnceCallback<void(bool)> callback,
                       std::unique_ptr<runtime::CallFunctionOnResult> result);
+  void OnFindElementForGetFieldValue(
+      base::OnceCallback<void(const std::string&)> callback,
+      std::unique_ptr<FindElementResult> element_result);
+  void OnGetValueAttribute(
+      base::OnceCallback<void(const std::string&)> callback,
+      std::unique_ptr<runtime::CallFunctionOnResult> result);
 
   // Weak pointer is fine here since it must outlive this web controller, which
   // is guaranteed by the owner of this object.
diff --git a/components/autofill_assistant/browser/web_controller_browsertest.cc b/components/autofill_assistant/browser/web_controller_browsertest.cc
index 56506e4..1630d3134 100644
--- a/components/autofill_assistant/browser/web_controller_browsertest.cc
+++ b/components/autofill_assistant/browser/web_controller_browsertest.cc
@@ -162,6 +162,24 @@
     ASSERT_FALSE(result->object_id.empty());
   }
 
+  std::string GetFieldValue(const std::vector<std::string>& selectors) {
+    base::RunLoop run_loop;
+    std::string result;
+    web_controller_->GetFieldValue(
+        selectors, base::BindOnce(&WebControllerBrowserTest::OnGetFieldValue,
+                                  base::Unretained(this),
+                                  run_loop.QuitClosure(), &result));
+    run_loop.Run();
+    return result;
+  }
+
+  void OnGetFieldValue(const base::Closure& done_callback,
+                       std::string* value_output,
+                       const std::string& value) {
+    *value_output = value;
+    std::move(done_callback).Run();
+  }
+
  private:
   std::unique_ptr<net::EmbeddedTestServer> http_server_;
   std::unique_ptr<WebController> web_controller_;
@@ -346,4 +364,14 @@
   EXPECT_EQ(node.value(), "BODY");
 }
 
+IN_PROC_BROWSER_TEST_F(WebControllerBrowserTest, GetFieldValue) {
+  std::vector<std::string> selectors;
+  selectors.emplace_back("#input");
+  EXPECT_EQ("helloworld", GetFieldValue(selectors));
+
+  selectors.clear();
+  selectors.emplace_back("#invalid_selector");
+  EXPECT_EQ("", GetFieldValue(selectors));
+}
+
 }  // namespace
diff --git a/components/browser_sync/profile_sync_components_factory_impl.cc b/components/browser_sync/profile_sync_components_factory_impl.cc
index 4e602db..a861e9c 100644
--- a/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -36,6 +36,7 @@
 #include "components/sync/driver/sync_client.h"
 #include "components/sync/driver/sync_driver_switches.h"
 #include "components/sync/engine/sync_engine.h"
+#include "components/sync/model_impl/forwarding_model_type_controller_delegate.h"
 #include "components/sync/model_impl/proxy_model_type_controller_delegate.h"
 #include "components/sync_bookmarks/bookmark_change_processor.h"
 #include "components/sync_bookmarks/bookmark_data_type_controller.h"
@@ -43,6 +44,7 @@
 #include "components/sync_bookmarks/bookmark_sync_service.h"
 #include "components/sync_sessions/session_data_type_controller.h"
 #include "components/sync_sessions/session_model_type_controller.h"
+#include "components/sync_sessions/session_sync_service.h"
 
 using base::FeatureList;
 using bookmarks::BookmarkModel;
@@ -249,11 +251,10 @@
         controllers.push_back(
             std::make_unique<sync_sessions::SessionModelTypeController>(
                 sync_client_->GetPrefService(),
-                std::make_unique<syncer::ProxyModelTypeControllerDelegate>(
-                    ui_thread_,
-                    base::BindRepeating(
-                        &syncer::SyncClient::GetControllerDelegateForModelType,
-                        base::Unretained(sync_client_), syncer::SESSIONS)),
+                std::make_unique<syncer::ForwardingModelTypeControllerDelegate>(
+                    sync_client_->GetSessionSyncService()
+                        ->GetControllerDelegate()
+                        .get()),
                 history_disabled_pref_));
       } else {
         controllers.push_back(std::make_unique<SessionDataTypeController>(
diff --git a/components/browser_sync/profile_sync_service.cc b/components/browser_sync/profile_sync_service.cc
index 12cfe5e..15db980 100644
--- a/components/browser_sync/profile_sync_service.cc
+++ b/components/browser_sync/profile_sync_service.cc
@@ -59,11 +59,7 @@
 #include "components/sync/syncable/directory.h"
 #include "components/sync/syncable/syncable_read_transaction.h"
 #include "components/sync_preferences/pref_service_syncable.h"
-#include "components/sync_sessions/favicon_cache.h"
-#include "components/sync_sessions/session_data_type_controller.h"
-#include "components/sync_sessions/session_sync_bridge.h"
-#include "components/sync_sessions/sessions_sync_manager.h"
-#include "components/sync_sessions/sync_sessions_client.h"
+#include "components/sync_sessions/session_sync_service.h"
 #include "components/version_info/version_info_values.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -257,33 +253,6 @@
       sync_service_url_, local_device_->GetSyncUserAgent(), url_loader_factory_,
       syncer::SyncStoppedReporter::ResultCallback());
 
-  // Not all |sync_client_|s will return a sync_sessions::SyncSessionsClient.
-  sync_sessions::SyncSessionsClient* sync_sessions_client =
-      sync_client_->GetSyncSessionsClient();
-  if (sync_sessions_client) {
-    if (base::FeatureList::IsEnabled(switches::kSyncUSSSessions)) {
-      DCHECK(sync_client_->GetSyncSessionsClient());
-      sessions_sync_manager_ =
-          std::make_unique<sync_sessions::SessionSyncBridge>(
-              sync_client_->GetSyncSessionsClient(), &sync_prefs_,
-              model_type_store_factory,
-              base::BindRepeating(
-                  &ProfileSyncService::NotifyForeignSessionUpdated,
-                  sync_enabled_weak_factory_.GetWeakPtr()),
-              std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
-                  syncer::SESSIONS,
-                  base::BindRepeating(&syncer::ReportUnrecoverableError,
-                                      channel_)));
-    } else {
-      sessions_sync_manager_ =
-          std::make_unique<sync_sessions::SessionsSyncManager>(
-              sync_client_->GetSyncSessionsClient(), &sync_prefs_,
-              base::BindRepeating(
-                  &ProfileSyncService::NotifyForeignSessionUpdated,
-                  sync_enabled_weak_factory_.GetWeakPtr()));
-    }
-  }
-
   device_info_sync_bridge_ = std::make_unique<syncer::DeviceInfoSyncBridge>(
       local_device_.get(), model_type_store_factory,
       std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
@@ -294,22 +263,6 @@
   data_type_controllers_ = BuildDataTypeControllerMap(
       sync_client_->CreateDataTypeControllers(local_device_.get()));
 
-  // If |sessions_sync_manager_| is null, make sure that certain data types
-  // are not enabled. This is because these data types will call into functions
-  // defined in ProfileSyncService which uses a |sessions_sync_manager_|.
-  if (!sessions_sync_manager_) {
-    DCHECK(data_type_controllers_.find(syncer::USER_EVENTS) ==
-           data_type_controllers_.end());
-    DCHECK(data_type_controllers_.find(syncer::FAVICON_IMAGES) ==
-           data_type_controllers_.end());
-    DCHECK(data_type_controllers_.find(syncer::FAVICON_TRACKING) ==
-           data_type_controllers_.end());
-    DCHECK(data_type_controllers_.find(syncer::PROXY_TABS) ==
-           data_type_controllers_.end());
-    DCHECK(data_type_controllers_.find(syncer::SESSIONS) ==
-           data_type_controllers_.end());
-  }
-
   if (gaia_cookie_manager_service_)
     gaia_cookie_manager_service_->AddObserver(this);
 
@@ -400,13 +353,7 @@
     return nullptr;
   }
 
-  DCHECK(sessions_sync_manager_);
-  return sessions_sync_manager_->GetOpenTabsUIDelegate();
-}
-
-sync_sessions::FaviconCache* ProfileSyncService::GetFaviconCache() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return sessions_sync_manager_->GetFaviconCache();
+  return sync_client_->GetSessionSyncService()->GetRawOpenTabsUIDelegate();
 }
 
 syncer::DeviceInfoTracker* ProfileSyncService::GetDeviceInfoTracker() const {
@@ -898,11 +845,6 @@
     observer.OnSyncCycleCompleted(this);
 }
 
-void ProfileSyncService::NotifyForeignSessionUpdated() {
-  for (auto& observer : observers_)
-    observer.OnForeignSessionUpdated(this);
-}
-
 void ProfileSyncService::NotifyShutdown() {
   for (auto& observer : observers_)
     observer.OnSyncShutdown(this);
@@ -1085,7 +1027,7 @@
       !syncer::HasSyncerError(snapshot.model_neutral_state())) {
     // Trigger garbage collection of old sessions now that we've downloaded
     // any new session data.
-    sessions_sync_manager_->ScheduleGarbageCollection();
+    sync_client_->GetSessionSyncService()->ScheduleGarbageCollection();
   }
   DVLOG(2) << "Notifying observers sync cycle completed";
   NotifySyncCycleCompleted();
@@ -2057,10 +1999,6 @@
   return auth_manager_->GetActiveAccountInfo().is_primary;
 }
 
-syncer::GlobalIdMapper* ProfileSyncService::GetGlobalIdMapper() const {
-  return sessions_sync_manager_->GetGlobalIdMapper();
-}
-
 base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return sync_js_controller_.AsWeakPtr();
@@ -2169,23 +2107,6 @@
   return auth_manager_->access_token();
 }
 
-syncer::SyncableService* ProfileSyncService::GetSessionsSyncableService() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!sessions_sync_manager_)
-    return nullptr;
-  return sessions_sync_manager_->GetSyncableService();
-}
-
-base::WeakPtr<syncer::ModelTypeControllerDelegate>
-ProfileSyncService::GetSessionSyncControllerDelegate() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  if (!sessions_sync_manager_)
-    return nullptr;
-  return sessions_sync_manager_->GetModelTypeSyncBridge()
-      ->change_processor()
-      ->GetControllerDelegate();
-}
-
 base::WeakPtr<syncer::ModelTypeControllerDelegate>
 ProfileSyncService::GetDeviceInfoSyncControllerDelegate() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -2242,6 +2163,12 @@
     engine_->FlushDirectory();
 }
 
+void ProfileSyncService::NotifyForeignSessionUpdated() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  for (auto& observer : observers_)
+    observer.OnForeignSessionUpdated(this);
+}
+
 base::MessageLoop* ProfileSyncService::GetSyncLoopForTest() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   return sync_thread_ ? sync_thread_->message_loop() : nullptr;
diff --git a/components/browser_sync/profile_sync_service.h b/components/browser_sync/profile_sync_service.h
index 3779277..4b6efca 100644
--- a/components/browser_sync/profile_sync_service.h
+++ b/components/browser_sync/profile_sync_service.h
@@ -60,21 +60,13 @@
 class SharedURLLoaderFactory;
 }  // namespace network
 
-namespace sync_sessions {
-class AbstractSessionsSyncManager;
-class FaviconCache;
-class OpenTabsUIDelegate;
-}  // namespace sync_sessions
-
 namespace syncer {
 class BackendMigrator;
 class BaseTransaction;
 class DeviceInfoSyncBridge;
 class DeviceInfoTracker;
-class LocalDeviceInfoProvider;
 class ModelTypeControllerDelegate;
 class NetworkResources;
-class SyncableService;
 class SyncTypePreferenceProvider;
 class TypeDebugInfoObserver;
 struct CommitCounters;
@@ -292,7 +284,6 @@
                        callback) override;
   AccountInfo GetAuthenticatedAccountInfo() const override;
   bool IsAuthenticatedAccountPrimary() const override;
-  syncer::GlobalIdMapper* GetGlobalIdMapper() const override;
 
   // Add a sync type preference provider. Each provider may only be added once.
   void AddPreferenceProvider(syncer::SyncTypePreferenceProvider* provider);
@@ -308,11 +299,6 @@
   void SetLocalDeviceInfoProviderForTest(
       std::unique_ptr<syncer::LocalDeviceInfoProvider> provider);
 
-  // Returns the SyncableService or USS bridge for syncer::SESSIONS.
-  syncer::SyncableService* GetSessionsSyncableService();
-  base::WeakPtr<syncer::ModelTypeControllerDelegate>
-  GetSessionSyncControllerDelegate();
-
   // Returns the ModelTypeControllerDelegate for syncer::DEVICE_INFO.
   base::WeakPtr<syncer::ModelTypeControllerDelegate>
   GetDeviceInfoSyncControllerDelegate();
@@ -444,8 +430,6 @@
   // once (before this object is destroyed).
   void Shutdown() override;
 
-  sync_sessions::FaviconCache* GetFaviconCache();
-
   // Overrides the NetworkResources used for Sync connections.
   // TODO(treib): Inject this in the ctor instead. As it is, it's possible that
   // the real NetworkResources were already used before the test had a chance
@@ -461,6 +445,12 @@
   // killed in the near future.
   void FlushDirectory() const;
 
+  // Notifies observers that foreign sessions have been updated.
+  // TODO(crbug.com/883199): This doesn't belong here, just like
+  // OnForeignSessionUpdated() doesn't belong in the observer. Let's move them
+  // to OpenTabsUIDelegate by introducing a similar observer mechanism.
+  virtual void NotifyForeignSessionUpdated();
+
   // Returns a serialized NigoriKey proto generated from the bootstrap token in
   // SyncPrefs. Will return the empty string if no bootstrap token exists.
   std::string GetCustomPassphraseKey() const;
@@ -548,7 +538,6 @@
   void NotifyObservers();
 
   void NotifySyncCycleCompleted();
-  void NotifyForeignSessionUpdated();
   void NotifyShutdown();
 
   void ClearStaleErrors();
@@ -746,10 +735,6 @@
 
   std::unique_ptr<syncer::LocalDeviceInfoProvider> local_device_;
 
-  // Locally owned SyncableService or ModelTypeSyncBridge implementations.
-  std::unique_ptr<sync_sessions::AbstractSessionsSyncManager>
-      sessions_sync_manager_;
-
   std::unique_ptr<syncer::DeviceInfoSyncBridge> device_info_sync_bridge_;
 
   std::unique_ptr<syncer::NetworkResources> network_resources_;
diff --git a/components/browser_sync/profile_sync_service_mock.h b/components/browser_sync/profile_sync_service_mock.h
index 0078459..e34a32d1 100644
--- a/components/browser_sync/profile_sync_service_mock.h
+++ b/components/browser_sync/profile_sync_service_mock.h
@@ -56,6 +56,7 @@
   MOCK_METHOD0(RequestStart, void());
   MOCK_METHOD1(RequestStop, void(ProfileSyncService::SyncStopDataFate));
 
+  MOCK_METHOD0(NotifyForeignSessionUpdated, void());
   MOCK_METHOD1(AddObserver, void(syncer::SyncServiceObserver*));
   MOCK_METHOD1(RemoveObserver, void(syncer::SyncServiceObserver*));
   MOCK_METHOD0(GetJsController, base::WeakPtr<syncer::JsController>());
diff --git a/components/browser_sync/profile_sync_test_util.cc b/components/browser_sync/profile_sync_test_util.cc
index 07ab16b5..cc965ce 100644
--- a/components/browser_sync/profile_sync_test_util.cc
+++ b/components/browser_sync/profile_sync_test_util.cc
@@ -22,7 +22,6 @@
 #include "components/sync/engine/sequenced_model_worker.h"
 #include "components/sync/engine/ui_model_worker.h"
 #include "components/sync/model/model_type_store_test_util.h"
-#include "components/sync_sessions/local_session_event_router.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_network_connection_tracker.h"
@@ -33,21 +32,11 @@
 
 namespace {
 
-class DummyRouter : public sync_sessions::LocalSessionEventRouter {
- public:
-  DummyRouter() {}
-  ~DummyRouter() override {}
-  void StartRoutingTo(
-      sync_sessions::LocalSessionEventHandler* handler) override {}
-  void Stop() override {}
-};
-
 class BundleSyncClient : public syncer::FakeSyncClient {
  public:
   BundleSyncClient(syncer::SyncApiComponentFactory* factory,
                    PrefService* pref_service,
                    syncer::ModelTypeStoreService* model_type_store_service,
-                   sync_sessions::SyncSessionsClient* sync_sessions_client,
                    autofill::PersonalDataManager* personal_data_manager,
                    const base::Callback<base::WeakPtr<syncer::SyncableService>(
                        syncer::ModelType type)>& get_syncable_service_callback,
@@ -62,7 +51,6 @@
   ~BundleSyncClient() override;
 
   PrefService* GetPrefService() override;
-  sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override;
   autofill::PersonalDataManager* GetPersonalDataManager() override;
   base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
       syncer::ModelType type) override;
@@ -76,7 +64,6 @@
  private:
   PrefService* const pref_service_;
   syncer::ModelTypeStoreService* const model_type_store_service_;
-  sync_sessions::SyncSessionsClient* const sync_sessions_client_;
   autofill::PersonalDataManager* const personal_data_manager_;
   const base::Callback<base::WeakPtr<syncer::SyncableService>(
       syncer::ModelType type)>
@@ -94,7 +81,6 @@
     syncer::SyncApiComponentFactory* factory,
     PrefService* pref_service,
     syncer::ModelTypeStoreService* model_type_store_service,
-    sync_sessions::SyncSessionsClient* sync_sessions_client,
     autofill::PersonalDataManager* personal_data_manager,
     const base::Callback<base::WeakPtr<syncer::SyncableService>(
         syncer::ModelType type)>& get_syncable_service_callback,
@@ -107,7 +93,6 @@
     : syncer::FakeSyncClient(factory),
       pref_service_(pref_service),
       model_type_store_service_(model_type_store_service),
-      sync_sessions_client_(sync_sessions_client),
       personal_data_manager_(personal_data_manager),
       get_syncable_service_callback_(get_syncable_service_callback),
       get_sync_service_callback_(get_sync_service_callback),
@@ -124,10 +109,6 @@
   return pref_service_;
 }
 
-sync_sessions::SyncSessionsClient* BundleSyncClient::GetSyncSessionsClient() {
-  return sync_sessions_client_;
-}
-
 autofill::PersonalDataManager* BundleSyncClient::GetPersonalDataManager() {
   return personal_data_manager_;
 }
@@ -238,9 +219,9 @@
 ProfileSyncServiceBundle::SyncClientBuilder::Build() {
   return std::make_unique<BundleSyncClient>(
       bundle_->component_factory(), bundle_->pref_service(),
-      &bundle_->model_type_store_service_, bundle_->sync_sessions_client(),
-      personal_data_manager_, get_syncable_service_callback_,
-      get_sync_service_callback_, get_bookmark_model_callback_,
+      &bundle_->model_type_store_service_, personal_data_manager_,
+      get_syncable_service_callback_, get_sync_service_callback_,
+      get_bookmark_model_callback_,
       activate_model_creation_ ? bundle_->db_thread() : nullptr,
       activate_model_creation_ ? base::SequencedTaskRunnerHandle::Get()
                                : nullptr,
@@ -270,11 +251,8 @@
   auth_service_.set_auto_post_fetch_response_on_message_loop(true);
   account_tracker_.Initialize(&pref_service_, base::FilePath());
   signin_manager_.Initialize(&pref_service_);
-  local_session_event_router_ = std::make_unique<DummyRouter>();
   identity_provider_ = std::make_unique<invalidation::ProfileIdentityProvider>(
       identity_manager());
-  ON_CALL(sync_sessions_client_, GetLocalSessionEventRouter())
-      .WillByDefault(testing::Return(local_session_event_router_.get()));
 }
 
 ProfileSyncServiceBundle::~ProfileSyncServiceBundle() {}
diff --git a/components/browser_sync/profile_sync_test_util.h b/components/browser_sync/profile_sync_test_util.h
index 90662510..37915d6 100644
--- a/components/browser_sync/profile_sync_test_util.h
+++ b/components/browser_sync/profile_sync_test_util.h
@@ -22,7 +22,6 @@
 #include "components/sync/driver/sync_api_component_factory_mock.h"
 #include "components/sync/model/test_model_type_store_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "components/sync_sessions/mock_sync_sessions_client.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "services/network/test/test_url_loader_factory.h"
 
@@ -34,10 +33,6 @@
 class PrefRegistrySyncable;
 }
 
-namespace sync_sessions {
-class LocalSessionEventRouter;
-}
-
 namespace browser_sync {
 
 // Call this to register preferences needed for ProfileSyncService creation.
@@ -144,10 +139,6 @@
     return &component_factory_;
   }
 
-  sync_sessions::MockSyncSessionsClient* sync_sessions_client() {
-    return &sync_sessions_client_;
-  }
-
   invalidation::ProfileIdentityProvider* identity_provider() {
     return identity_provider_.get();
   }
@@ -174,10 +165,6 @@
   FakeGaiaCookieManagerService gaia_cookie_manager_service_;
   identity::IdentityManager identity_manager_;
   testing::NiceMock<syncer::SyncApiComponentFactoryMock> component_factory_;
-  std::unique_ptr<sync_sessions::LocalSessionEventRouter>
-      local_session_event_router_;
-  testing::NiceMock<sync_sessions::MockSyncSessionsClient>
-      sync_sessions_client_;
   std::unique_ptr<invalidation::ProfileIdentityProvider> identity_provider_;
   invalidation::FakeInvalidationService fake_invalidation_service_;
   network::TestURLLoaderFactory test_url_loader_factory_;
diff --git a/components/dom_distiller/content/renderer/distiller_native_javascript.cc b/components/dom_distiller/content/renderer/distiller_native_javascript.cc
index 3f9321c3e..10c012c 100644
--- a/components/dom_distiller/content/renderer/distiller_native_javascript.cc
+++ b/components/dom_distiller/content/renderer/distiller_native_javascript.cc
@@ -54,10 +54,12 @@
     v8::Local<v8::Object> javascript_object,
     const std::string& name,
     const base::Callback<Sig> callback) {
+  v8::Local<v8::Context> context = isolate->GetCurrentContext();
   // Get the isolate associated with this object.
-  javascript_object->Set(
-      gin::StringToSymbol(isolate, name),
-      gin::CreateFunctionTemplate(isolate, callback)->GetFunction());
+  javascript_object->Set(gin::StringToSymbol(isolate, name),
+                         gin::CreateFunctionTemplate(isolate, callback)
+                             ->GetFunction(context)
+                             .ToLocalChecked());
 }
 
 void DistillerNativeJavaScript::EnsureServiceConnected() {
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
index f53ce4e..cfc076b 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
@@ -397,7 +397,8 @@
   return Java_WebContentsDelegateAndroid_getBottomControlsHeight(env, obj);
 }
 
-bool WebContentsDelegateAndroid::DoBrowserControlsShrinkBlinkSize() const {
+bool WebContentsDelegateAndroid::DoBrowserControlsShrinkRendererSize(
+    const content::WebContents* contents) const {
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
   if (obj.is_null())
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.h b/components/embedder_support/android/delegate/web_contents_delegate_android.h
index 643068d..8a48fab 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.h
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.h
@@ -116,7 +116,8 @@
                            const GURL& url) override;
   int GetTopControlsHeight() const override;
   int GetBottomControlsHeight() const override;
-  bool DoBrowserControlsShrinkBlinkSize() const override;
+  bool DoBrowserControlsShrinkRendererSize(
+      const content::WebContents* contents) const override;
 
  protected:
   base::android::ScopedJavaLocalRef<jobject> GetJavaDelegate(JNIEnv* env) const;
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index 92c7faa4..871246d 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -70,6 +70,22 @@
 const base::Feature kExperimentalKeywordMode{"ExperimentalKeywordMode",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
 
+// Feature used to enable pedal suggestion as either in-suggestion side button
+// or dedicated suggestion beneath triggering suggestion.
+const base::Feature kOmniboxPedalSuggestions{"OmniboxPedalSuggestions",
+                                             base::FEATURE_DISABLED_BY_DEFAULT};
+constexpr base::FeatureParam<OmniboxFieldTrial::PedalSuggestionMode>::Option
+    kPedalSuggestionModeOptions[] = {
+        {OmniboxFieldTrial::PedalSuggestionMode::IN_SUGGESTION,
+         "in_suggestion"},
+        {OmniboxFieldTrial::PedalSuggestionMode::DEDICATED, "dedicated"},
+};
+constexpr base::FeatureParam<OmniboxFieldTrial::PedalSuggestionMode>
+    pedal_suggestion_mode{&kOmniboxPedalSuggestions,
+                          OmniboxFieldTrial::kPedalSuggestionModeParam,
+                          OmniboxFieldTrial::PedalSuggestionMode::DEDICATED,
+                          &kPedalSuggestionModeOptions};
+
 // Feature used to enable clipboard provider, which provides the user with
 // suggestions of the URL in the user's clipboard (if any) upon omnibox focus.
 const base::Feature kEnableClipboardProvider {
@@ -748,6 +764,15 @@
          base::FeatureList::IsEnabled(features::kExperimentalUi);
 }
 
+OmniboxFieldTrial::PedalSuggestionMode
+OmniboxFieldTrial::GetPedalSuggestionMode() {
+  // Disabled case is handled specially, as no parameter values are specified.
+  if (!base::FeatureList::IsEnabled(omnibox::kOmniboxPedalSuggestions)) {
+    return PedalSuggestionMode::NONE;
+  }
+  return omnibox::pedal_suggestion_mode.Get();
+}
+
 bool OmniboxFieldTrial::IsHideSteadyStateUrlSchemeAndSubdomainsEnabled() {
 #if defined(OS_MACOSX)
 #if BUILDFLAG(MAC_VIEWS_BROWSER)
@@ -857,6 +882,8 @@
 const char OmniboxFieldTrial::kUIMaxAutocompleteMatchesParam[] =
     "UIMaxAutocompleteMatches";
 const char OmniboxFieldTrial::kUIVerticalMarginParam[] = "UIVerticalMargin";
+const char OmniboxFieldTrial::kPedalSuggestionModeParam[] =
+    "PedalSuggestionMode";
 
 const char OmniboxFieldTrial::kZeroSuggestRedirectToChromeExperimentIdParam[] =
     "ZeroSuggestRedirectToChromeExperimentID";
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index fc8b6f6..a2cd9c6 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -31,6 +31,7 @@
 extern const base::Feature kOmniboxTailSuggestions;
 extern const base::Feature kOmniboxTabSwitchSuggestions;
 extern const base::Feature kExperimentalKeywordMode;
+extern const base::Feature kOmniboxPedalSuggestions;
 extern const base::Feature kEnableClipboardProvider;
 extern const base::Feature kSearchProviderWarmUpOnFocus;
 extern const base::Feature kZeroSuggestRedirectToChrome;
@@ -156,6 +157,13 @@
     EMPHASIZE_NEVER = 3
   };
 
+  // These are the discrete possibilities for pedal behavior.
+  enum class PedalSuggestionMode {
+    NONE,
+    IN_SUGGESTION,
+    DEDICATED,
+  };
+
   // ---------------------------------------------------------
   // For any experiment that's part of the bundled omnibox field trial.
 
@@ -428,6 +436,9 @@
   // or the #upcoming-ui-features flag is enabled.
   static bool IsTabSwitchSuggestionsEnabled();
 
+  // Returns the #omnibox-pedal-suggestions feature's mode parameter as enum.
+  static PedalSuggestionMode GetPedalSuggestionMode();
+
   // Returns true if either the steady-state elision flag or the
   // #upcoming-ui-features flag is enabled.
   static bool IsHideSteadyStateUrlSchemeAndSubdomainsEnabled();
@@ -503,6 +514,7 @@
   // Parameter names used by UI experiments.
   static const char kUIMaxAutocompleteMatchesParam[];
   static const char kUIVerticalMarginParam[];
+  static const char kPedalSuggestionModeParam[];
 
   // Parameter names used by Zero Suggest Redirect to Chrome.
   static const char kZeroSuggestRedirectToChromeExperimentIdParam[];
diff --git a/components/onc/docs/onc_spec.md b/components/onc/docs/onc_spec.md
index a272f884..ae9813d 100644
--- a/components/onc/docs/onc_spec.md
+++ b/components/onc/docs/onc_spec.md
@@ -141,6 +141,63 @@
     however it should not be considered an error if no such field is present.
 ---
 
+## Global Network Configuration
+
+Field **GlobaNetworkConfiguration** has the [GlobalNetworkConfiguration]
+(#GlobalNetworkConfiguration-type) type.
+
+### GlobalNetworkConfiguration type
+
+The [GlobalNetworkConfiguration](#GlobalNetworkConfiguration-type) contains
+settings which apply to all of the networks that the device may connect to. The
+client supports this only in device-level policy; the client-side ONC validator
+fails if it appears in user policy.
+To avoid bricking devices, these policies will only be enforced in user
+sessions. The login screen ignores these policies and may still be used for
+fetching new policy or logging in.
+A [Help Center article](https://support.google.com/chrome/a/answer/6326250)
+warns admins of the implications of mis-using this policy for Chrome OS.
+
+
+* **AllowOnlyPolicyNetworksToAutoconnect**
+    * (optional, defaults to false) - **boolean**
+    * When this field is present and set to true, on startup the device will
+      only auto connect to those networks that are present in its policy. This
+      is necessary for devices that are used as kiosks, for example, so that
+      they can’t be hijacked by some other user on startup.
+
+* **AllowOnlyPolicyNetworksToConnect**
+    * (optional, defaults to false) - **boolean**
+    * When this field is present and set to true, only networks present in
+      policy may be connected to. This allows schools to enforce that only
+      known-good networks (e.g., filtered student networks) may be used.
+      Existing connections to unmanaged networks will be disconnected on policy
+      fetch.
+
+* **AllowOnlyPolicyNetworksToConnectIfAvailable**
+    * (optional, defaults to false) - **boolean**
+    * When this field is present, set to true and a policy network is in range,
+      only policy networks may be connected to. If no managed network is in
+      range (e.g. user’s home), the device may connect to any network. If
+      enabled and a network scan shows a new policy managed network, the device
+      will automatically switch to the managed network.
+
+* **BlacklistedHexSSIDs**
+    * (optional) - **array of string**
+    * List of strings containing blacklisted hex SSIDs. Networks included in
+      this list will not be connectable. Existing connections to networks
+      contained in this list will be disconnected on policy fetch.
+
+* **DisableNetworkTypes**
+    * (optional) - **array of string**
+    * Allowed values are:
+        * Cellular
+        * Ethernet
+        * WiFi
+        * WiMAX
+        * Tether
+    * List of strings containing disabled network interfaces.
+
 ## Network Configuration
 
 Field **NetworkConfigurations** is an array of
@@ -164,7 +221,7 @@
       if **NameServersConfigType** is specified) - **string**
     * Allowed values are:
         * *DHCP*
-        * *Static*.
+        * *Static*
     * Determines whether the IP Address configuration is statically configured,
       see **StaticIPConfig**, or automatically configured
       using DHCP.
@@ -174,7 +231,7 @@
     if **IPAddressConfigType** is specified) - **string**
     * Allowed values are:
         * *DHCP*
-        * *Static*.
+        * *Static*
     * Determines whether the NameServers configuration is statically configured,
       see **StaticIPConfig**, or automatically configured
       using DHCP.
@@ -1805,6 +1862,29 @@
 
 * "${PASSWORD}foo" -> "${PASSWORD}foo"
 
+## Recommended Values
+When a policy is providing ONC configurations, the assumption is that all values
+are mandatory and immutable. To specify values that can be overridden by a user
+(e.g. proxy or username), use the **Recommended** property.
+
+* **Recommended**
+  * (optional) - **array of string**
+  * The field(s) with the names in the strings in this array are to be treated
+    as recommended settings. Any fields not mentioned in this array remain
+    mandatory. This also means that fields that are not mentioned in the array
+    and also not mentioned in the objects are mandatory and have the default
+    value of the field. If not present, all fields are mandatory. Fields that
+    are objects or arrays of objects included in Recommended will be ignored. In
+    those cases, the nested objects should have their own Recommended fields. A
+    special case is if the string "." is included in the list. When this is
+    present, it means that the entire certificate or network can be forgotten or
+    deleted by the user. Including the "." has no implications on the rest of
+    the settings. For instance, a network may have Recommended set to [ "." ],
+    in which case its settings may not be changed by the user, but the whole
+    network can be forgotten by the user.  The "." is valid in a Certificate
+    object and the NetworkConfiguration object, it is ignored elsewhere.
+
+
 ## Detection
 
 This format should be sent in files ending in the .onc extension. When
@@ -1831,6 +1911,25 @@
 
 ## Examples
 
+### GlobalNetworkConfiguration Example
+
+In this example, we only allow managed networks to auto connect and
+disallow any other networks if a managed network is available. We also blacklist
+the "Guest" network (hex("Guest")=4775657374) and disable Cellular and WiMAX
+services.
+```
+{
+  "Type": "UnencryptedConfiguration",
+  "GlobalNetworkConfiguration": {
+    "AllowOnlyPolicyNetworksToAutoconnect": true,
+    “AllowOnlyPolicyNetworksToConnect”: false,
+    “AllowOnlyPolicyNetworksToConnectIfAvailable”: true,
+    “BlacklistedHexSSIDs”: [“4775657374”],
+    "DisableNetworkTypes": ["Cellular", "WiMAX"]
+  }
+}
+```
+
 ### Simple format example: PEAP/MSCHAPv2 network (per device)
 
 ```
@@ -1948,6 +2047,40 @@
 }
 ```
 
+### Recommended values example
+
+In this example, the EAP Identity and Password are marked as recommended, i.e.
+they can be edited by the user. All other values are mandatory.
+
+```
+{
+  "Type": "UnencryptedConfiguration",
+  "GlobalNetworkConfiguration": {},
+  "NetworkConfigurations": [
+    {
+      "GUID": "{485e6176-dd34-6b6d-1234}",
+      "Name": "wifi_test",
+      "Type": "WiFi",
+      "WiFi": {
+        "SSID": "wifi_test",
+        "Security": "WPA-EAP",
+        "AutoConnect": true,
+        "EAP": {
+          "Inner": "MSCHAPv2",
+          "Outer": "PEAP",
+          "SaveCredentials": true,
+          "UseSystemCAs": false,
+          "Identity": "john-doe",
+          "Password": "secret-password-123",
+          "Recommended": ["Identity", "Password"]
+        }
+      }
+    }
+    }
+  ]
+}
+```
+
 
 ## Standalone editor
 
diff --git a/components/password_manager/core/browser/BUILD.gn b/components/password_manager/core/browser/BUILD.gn
index 726fb22a..e2d3371 100644
--- a/components/password_manager/core/browser/BUILD.gn
+++ b/components/password_manager/core/browser/BUILD.gn
@@ -76,6 +76,8 @@
     "import/password_csv_reader.h",
     "import/password_importer.cc",
     "import/password_importer.h",
+    "invalid_realm_credential_cleaner.cc",
+    "invalid_realm_credential_cleaner.h",
     "keychain_migration_status_mac.h",
     "log_manager.cc",
     "log_manager.h",
@@ -381,6 +383,7 @@
     "import/csv_reader_unittest.cc",
     "import/password_csv_reader_unittest.cc",
     "import/password_importer_unittest.cc",
+    "invalid_realm_credential_cleaner_unittest.cc",
     "log_manager_unittest.cc",
     "log_router_unittest.cc",
     "login_database_unittest.cc",
diff --git a/components/password_manager/core/browser/blacklisted_duplicates_cleaner_unittest.cc b/components/password_manager/core/browser/blacklisted_duplicates_cleaner_unittest.cc
index eebef9b..f65f18d 100644
--- a/components/password_manager/core/browser/blacklisted_duplicates_cleaner_unittest.cc
+++ b/components/password_manager/core/browser/blacklisted_duplicates_cleaner_unittest.cc
@@ -81,7 +81,13 @@
   prefs()->registry()->RegisterBooleanPref(
       prefs::kDuplicatedBlacklistedCredentialsRemoved, false);
 
-  password_manager_util::DeleteBlacklistedDuplicates(store(), prefs(), 0);
+  // In this test we are explicitly only testing the clean up of duplicated
+  // credentials and setting this true will prevent making another unrelated
+  // clean-up.
+  prefs()->registry()->RegisterBooleanPref(
+      prefs::kCredentialsWithWrongSignonRealmRemoved, true);
+
+  password_manager_util::RemoveUselessCredentials(store(), prefs(), 0);
   scoped_task_environment.RunUntilIdle();
 
   // Check that one of the next two forms was removed.
@@ -93,7 +99,7 @@
   EXPECT_FALSE(
       prefs()->GetBoolean(prefs::kDuplicatedBlacklistedCredentialsRemoved));
 
-  password_manager_util::DeleteBlacklistedDuplicates(store(), prefs(), 0);
+  password_manager_util::RemoveUselessCredentials(store(), prefs(), 0);
   scoped_task_environment.RunUntilIdle();
   EXPECT_TRUE(
       prefs()->GetBoolean(prefs::kDuplicatedBlacklistedCredentialsRemoved));
diff --git a/components/password_manager/core/browser/invalid_realm_credential_cleaner.cc b/components/password_manager/core/browser/invalid_realm_credential_cleaner.cc
new file mode 100644
index 0000000..aa72fc8
--- /dev/null
+++ b/components/password_manager/core/browser/invalid_realm_credential_cleaner.cc
@@ -0,0 +1,242 @@
+// 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/password_manager/core/browser/invalid_realm_credential_cleaner.h"
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <string>
+#include <tuple>
+#include <utility>
+
+#include "base/strings/string_piece.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_service.h"
+#include "url/gurl.h"
+
+namespace password_manager {
+
+namespace {
+
+using FormVector = std::vector<std::unique_ptr<autofill::PasswordForm>>;
+
+// This type defines a subset of PasswordForm where the first argument is the
+// date_created, the second argument is the origin (excluding protocol), and the
+// third argument is the username of the form.
+// Excluding protocol from an url means, for example, that "http://google.com/"
+// after excluding protocol becomes "google.com/".
+using FormKeyForHttpMatch = std::tuple<base::Time, std::string, base::string16>;
+
+// This type defines a subset of PasswordForm where the first argument is
+// the web origin (given by origin.GetOrigin().spec()) and the second
+// argument is the username of the form.
+using FormKeyForHttpsMatch = std::pair<std::string, base::string16>;
+
+// This function moves the elements from |forms| for which predicate |p| is true
+// to |.first| and the rest of elements to |.second|.
+template <typename UnaryPredicate>
+std::pair<FormVector, FormVector> SplitFormsBy(FormVector forms,
+                                               UnaryPredicate p) {
+  auto first_false = std::partition(forms.begin(), forms.end(), p);
+
+  return std::make_pair(FormVector(std::make_move_iterator(forms.begin()),
+                                   std::make_move_iterator(first_false)),
+                        FormVector(std::make_move_iterator(first_false),
+                                   std::make_move_iterator(forms.end())));
+}
+
+// Returns the fields from PasswordForm necessary to match an HTTPS form with
+// an invalid signon_realm with the HTTP form credentials from which HTTPS form
+// was created.
+FormKeyForHttpMatch GetFormKeyForHttpMatch(const autofill::PasswordForm& form) {
+  return {form.date_created, form.origin.GetContent(), form.username_value};
+}
+
+// Returns the fields from PasswordForm necessary to match an HTTPS form with an
+// invalid signon_realm with an HTTPS form with a valid signon_realm. This
+// function is used only for matching an HTML credential with an invalid
+// signon_realm with an HTML credentils with a valid signon_realm.
+FormKeyForHttpsMatch GetFormKeyForHttpsMatch(
+    const autofill::PasswordForm& form) {
+  DCHECK_EQ(form.scheme, autofill::PasswordForm::Scheme::SCHEME_HTML);
+  return {form.origin.GetOrigin().spec(), form.username_value};
+}
+
+// Removes HTML forms with HTTPS protocol which have an invalid signon_realm
+// from the password store as follow:
+// (1) Credentials with the signon_realm equal to the web origin are ignored.
+// (2) Blacklisted credentials with an invalid signom_realm are removed.
+// (3) Credentials for which an equivalent HTTP credential exists in the
+// password store are removed, relying on migrator to recreate them.
+// (4) Credentials for which an equivalent HTTPS credential exists in the
+// password store are removed as well, because they are already correctly
+// recreated.
+// (5) If none of these steps happened then the credentials are not
+// fixed and they could not be re-created from HTTP credentials. Thus, this
+// function will fix their signon_realm.
+// Note that credentials with an invalid signon_realm cannot be fixed without
+// checking steps (3) and (4) because it might lead to overwriting the most
+// up-to-date password value for that site.
+void RemoveHtmlCredentialsWithInvalidRealm(
+    PasswordStore* store,
+    const std::map<FormKeyForHttpMatch, std::string>& http_credentials_map,
+    const std::set<FormKeyForHttpsMatch>& https_credentials_keys,
+    FormVector https_html_forms) {
+  DCHECK(std::all_of(
+      https_html_forms.begin(), https_html_forms.end(), [](const auto& form) {
+        return form->scheme == autofill::PasswordForm::Scheme::SCHEME_HTML;
+      }));
+
+  // Ignore credentials which are valid.
+  base::EraseIf(https_html_forms, [](const auto& form) {
+    return form->signon_realm == form->origin.GetOrigin().spec();
+  });
+
+  for (const auto& form : https_html_forms) {
+    store->RemoveLogin(*form);
+
+    if (form->blacklisted_by_user ||
+        base::ContainsKey(http_credentials_map,
+                          GetFormKeyForHttpMatch(*form)) ||
+        base::ContainsKey(https_credentials_keys,
+                          GetFormKeyForHttpsMatch(*form))) {
+      // If form is blacklisted then it was useless so far.
+      // If there is an HTTP match then credentials can be recovered.
+      // If there is an HTTPS match then credentials are already recovered.
+      // In all cases credentials can be safely removed.
+      continue;
+    }
+    // Fix the signon_realm.
+    form->signon_realm = form->origin.GetOrigin().spec();
+    store->AddLogin(*form);
+  }
+}
+
+// Removes non-HTML forms with HTTPS protocol which have an invalid signon_realm
+// from the password store as follow:
+// (1) Search for an HTTP form with the same date of creation, same origin and
+// same username.
+// (2) If such a corresponding HTTP credential exists then compare their
+// signon_realm (excluding protocol). If the signon_realms are different,
+// HTTPS credentials will be deleted from the password store.
+void RemoveNonHtmlCredentialsWithInvalidRealm(
+    PasswordStore* store,
+    const std::map<FormKeyForHttpMatch, std::string>& http_credentials_map,
+    FormVector https_non_html_forms) {
+  DCHECK(std::all_of(https_non_html_forms.begin(), https_non_html_forms.end(),
+                     [](const auto& form) {
+                       return form->scheme !=
+                              autofill::PasswordForm::Scheme::SCHEME_HTML;
+                     }));
+  // Credentials with signon_realm different from the origin were not created by
+  // faulty migration and are ignored.
+  base::EraseIf(https_non_html_forms, [](const auto& form) {
+    return form->origin.spec() != form->signon_realm;
+  });
+
+  for (const auto& form : https_non_html_forms) {
+    // Match HTTPS credentials with HTTP credentials if they have same
+    // date_created, origin (excluding protocol) and username_value.
+    // Because only forms with signon_realm equal to the origin URL remained at
+    // this point (see the erasing above), GURL(form->signon_realm) is the same
+    // as form->origin.
+    auto it = http_credentials_map.find(GetFormKeyForHttpMatch(*form));
+    if (it != http_credentials_map.end() &&
+        it->second != form->origin.GetContent()) {
+      // The password store contains a corresponding HTTP credential, current
+      // HTTPS credential being the migrated version of the HTTP credential.
+      // Thus, they must have the same signon_realm (excluding their
+      // protocol). Because the current signon_realm (excluding protocol) of
+      // the HTTPS credential is different from the signon_realm (excluding
+      // protocol) given by the corresponding HTTP credential (which is the
+      // good one) means that the HTTPS credential was faulty migrated and
+      // thus the form can be removed.
+      store->RemoveLogin(*form);
+    }
+  }
+}
+
+}  // namespace
+
+InvalidRealmCredentialCleaner::InvalidRealmCredentialCleaner(
+    scoped_refptr<PasswordStore> store,
+    PrefService* prefs)
+    : store_(std::move(store)), prefs_(prefs) {}
+
+InvalidRealmCredentialCleaner::~InvalidRealmCredentialCleaner() = default;
+
+void InvalidRealmCredentialCleaner::StartCleaning(Observer* observer) {
+  DCHECK(observer);
+  DCHECK(!observer_);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  observer_ = observer;
+  remaining_cleaning_tasks_ = 2;
+  store_->GetBlacklistLogins(this);
+  store_->GetAutofillableLogins(this);
+}
+
+void InvalidRealmCredentialCleaner::OnGetPasswordStoreResults(
+    FormVector results) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Non HTTP or HTTPS credentials are ignored.
+  base::EraseIf(results, [](const auto& form) {
+    return !form->origin.SchemeIsHTTPOrHTTPS();
+  });
+
+  // Separate HTTP and HTTPS credentials.
+  FormVector http_forms, https_forms;
+  std::tie(http_forms, https_forms) = SplitFormsBy(
+      std::move(results),
+      [](const auto& form) { return form->origin.SchemeIs(url::kHttpScheme); });
+
+  // Map from (date_created, origin (excluding protocol), username_value) of
+  // HTTP forms to the expected signon_realm (excluding the protocol).
+  std::map<FormKeyForHttpMatch, std::string> http_credentials_map;
+  for (const auto& form : http_forms) {
+    base::StringPiece signon_realm = form->signon_realm;
+    // Find the web origin in the signon_realm and remove what is before it.
+    // This will result in removing the protocol ("http://").
+    signon_realm = signon_realm.substr(
+        signon_realm.find(form->origin.GetOrigin().GetContent()));
+    http_credentials_map.emplace(GetFormKeyForHttpMatch(*form), signon_realm);
+  }
+
+  // Separate HTML and non-HTML HTTPS credentials.
+  FormVector https_html_forms, https_non_html_forms;
+  std::tie(https_html_forms, https_non_html_forms) =
+      SplitFormsBy(std::move(https_forms), [](const auto& form) {
+        return form->scheme == autofill::PasswordForm::Scheme::SCHEME_HTML;
+      });
+
+  // This set indicates if the password store contains an HTML form with HTTPS
+  // protocol with a specific web origin and username. Only forms with the
+  // correct signon_realm are inserted in this set.
+  std::set<FormKeyForHttpsMatch> https_credentials_keys;
+  for (const auto& form : https_html_forms) {
+    if (form->signon_realm == form->origin.GetOrigin().spec())
+      https_credentials_keys.insert(GetFormKeyForHttpsMatch(*form));
+  }
+
+  RemoveHtmlCredentialsWithInvalidRealm(store_.get(), http_credentials_map,
+                                        https_credentials_keys,
+                                        std::move(https_html_forms));
+
+  RemoveNonHtmlCredentialsWithInvalidRealm(store_.get(), http_credentials_map,
+                                           std::move(https_non_html_forms));
+  if (--remaining_cleaning_tasks_ == 0)
+    CleaningFinished();
+}
+
+void InvalidRealmCredentialCleaner::CleaningFinished() {
+  // Set the preference in order to avoid calling clean-up again.
+  prefs_->SetBoolean(prefs::kCredentialsWithWrongSignonRealmRemoved, true);
+
+  observer_->CleaningCompleted();
+}
+
+}  // namespace password_manager
\ No newline at end of file
diff --git a/components/password_manager/core/browser/invalid_realm_credential_cleaner.h b/components/password_manager/core/browser/invalid_realm_credential_cleaner.h
new file mode 100644
index 0000000..a060b0c0
--- /dev/null
+++ b/components/password_manager/core/browser/invalid_realm_credential_cleaner.h
@@ -0,0 +1,78 @@
+// 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_PASSWORD_MANAGER_CORE_BROWSER_INVALID_REALM_CREDENTIAL_CLEANER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_INVALID_REALM_CREDENTIAL_CLEANER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
+#include "components/password_manager/core/browser/credentials_cleaner.h"
+#include "components/password_manager/core/browser/password_store_consumer.h"
+
+namespace autofill {
+struct PasswordForm;
+}  // namespace autofill
+
+class PrefService;
+
+namespace password_manager {
+
+class PasswordStore;
+
+// This class removes HTTPS credentials with invalid signon_realm created by
+// faulty HTTP->HTTPS migration. See https://crbug.com/881731 for details.
+// TODO(https://crbug.com/880090): Remove the code once majority of the users
+// executed it.
+class InvalidRealmCredentialCleaner : public PasswordStoreConsumer,
+                                      public CredentialsCleaner {
+ public:
+  // The cleaning will be made for credentials from |store|.
+  // A preference from |prefs| is used to set the cleaning state as finished.
+  InvalidRealmCredentialCleaner(scoped_refptr<PasswordStore> store,
+                                PrefService* prefs);
+
+  ~InvalidRealmCredentialCleaner() override;
+
+  // CredentialsCleaner:
+  void StartCleaning(Observer* observer) override;
+
+  // PasswordStoreConsumer:
+  void OnGetPasswordStoreResults(
+      std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
+
+ private:
+  // After the clean-up is done, this function will inform the |observer_| about
+  // clean-up completion and set a preference in |prefs_| to true to avoid
+  // calling clean-up multiple times.
+  void CleaningFinished();
+
+  // Clean-up is performed on |store_|.
+  scoped_refptr<PasswordStore> store_;
+
+  // |prefs_| is not an owning pointer. It is used to record that the clean-up
+  // happened and thus does not have to happen again.
+  PrefService* prefs_;
+
+  // Used to signal completion of the clean-up. It is null until
+  // StartCleaning is called.
+  Observer* observer_ = nullptr;
+
+  // Indicates the number of responses from PasswordStore remaining to be
+  // processed. The number will be set in StartCleaning method.
+  int remaining_cleaning_tasks_ = 0;
+
+  // This guard checks that all operations performed on
+  // |remaining_cleaning_tasks_| run on the same sequence.
+  SEQUENCE_CHECKER(sequence_checker_);
+
+  DISALLOW_COPY_AND_ASSIGN(InvalidRealmCredentialCleaner);
+};
+
+}  // namespace password_manager
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_INVALID_REALM_CREDENTIAL_CLEANER_H_
\ No newline at end of file
diff --git a/components/password_manager/core/browser/invalid_realm_credential_cleaner_unittest.cc b/components/password_manager/core/browser/invalid_realm_credential_cleaner_unittest.cc
new file mode 100644
index 0000000..620f0762
--- /dev/null
+++ b/components/password_manager/core/browser/invalid_realm_credential_cleaner_unittest.cc
@@ -0,0 +1,404 @@
+// 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/password_manager/core/browser/invalid_realm_credential_cleaner.h"
+
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/browser/test_password_store.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace password_manager {
+
+namespace {
+
+struct MigrationFormsPair {
+  autofill::PasswordForm http_form;
+  autofill::PasswordForm migrated_https_form;
+};
+
+constexpr struct HttpMatchState {
+  bool same_creation_time;
+  bool same_origin;
+  bool same_username;
+  // This member is just the logical conjunction on the members above.
+  bool is_matching;
+} kHttpMatchStates[] = {
+    {false, false, false, false}, {false, false, true, false},
+    {false, true, false, false},  {false, true, true, false},
+    {true, false, false, false},  {true, false, true, false},
+    {true, true, false, false},   {true, true, true, true},
+};
+
+// |kDates|, |kOrigins|, and |kUsernames| are used to easily manipulate the
+// fields of HTTP and HTTPS forms that should be equal. The HTTP forms will
+// use the component [1] from these arrays. The HTTPS forms will use [1] if the
+// field (given by array name) should be the same and [0] otherwise. Component
+// [2] is used when we want to create a form with the field different from both
+// ([0] and [1]).
+const base::Time kDates[] = {base::Time::FromDoubleT(100),
+                             base::Time::FromDoubleT(200),
+                             base::Time::FromDoubleT(300)};
+
+const GURL kOrigins[] = {GURL("https://example.org/path-0/"),
+                         GURL("https://example.org/path-1/"),
+                         GURL("https://google.com/path/")};
+
+const base::string16 kUsernames[] = {base::ASCIIToUTF16("user0"),
+                                     base::ASCIIToUTF16("user1")};
+
+bool StoreContains(TestPasswordStore* store,
+                   const autofill::PasswordForm& form) {
+  const auto it = store->stored_passwords().find(form.signon_realm);
+  return it != store->stored_passwords().end() &&
+         base::ContainsValue(it->second, form);
+}
+
+// Returns the HTTP form for given parameters and the migrated version of that
+// form.
+MigrationFormsPair GetCredentialsFrom(bool is_blacklisted,
+                                      bool invalid_signon_realm,
+                                      const HttpMatchState& http_match_state) {
+  autofill::PasswordForm http_form;
+  http_form.origin = GURL("http://example.org/path-1/");
+  http_form.signon_realm = "http://example.org/";
+  http_form.date_created = kDates[1];
+  http_form.username_value =
+      (is_blacklisted ? base::string16() : kUsernames[1]);
+  http_form.blacklisted_by_user = is_blacklisted;
+
+  autofill::PasswordForm https_form;
+  https_form.origin = kOrigins[http_match_state.same_origin];
+  https_form.signon_realm = (invalid_signon_realm ? https_form.origin.spec()
+                                                  : "https://example.org/");
+  https_form.date_created = kDates[http_match_state.same_creation_time];
+  https_form.username_value =
+      (is_blacklisted ? base::string16()
+                      : kUsernames[http_match_state.same_username]);
+  https_form.blacklisted_by_user = is_blacklisted;
+  return {http_form, https_form};
+}
+
+}  // namespace
+
+// This test checks that HTML credentials are correctly removed for the case
+// when both (HTTP and HTTPS credentials) are blacklisted, or both are not
+// blacklsited.
+TEST(InvalidRealmCredentialCleanerTest,
+     RemoveHtmlCredentialsWithWrongSignonRealm) {
+  enum class ExpectedOperation { kNothing, kFix, kDelete };
+
+  static constexpr struct HttpsMatchState {
+    bool same_signon_realm;
+    bool same_username;
+    // This member is just the logical conjunction on the members above.
+    bool is_matching;
+  } kHttpsMatchStates[] = {{false, false, false},
+                           {false, true, false},
+                           {true, false, false},
+                           {true, true, true}};
+
+  struct TestCase {
+    bool is_blacklisted;
+    bool invalid_signon_realm;
+    HttpMatchState http_state;
+    HttpsMatchState https_state;
+    ExpectedOperation expected_operation;
+  };
+
+  std::vector<TestCase> cases;
+  for (bool is_blacklisted : {true, false}) {
+    for (bool invalid_signon_realm : {true, false}) {
+      for (const HttpMatchState& http_state : kHttpMatchStates) {
+        for (const HttpsMatchState& https_state : kHttpsMatchStates) {
+          // This state is invalid since blacklisted credentials have username
+          // cleared.
+          if (is_blacklisted &&
+              (!http_state.same_username || !https_state.same_username))
+            continue;
+
+          ExpectedOperation expected_operation = ExpectedOperation::kNothing;
+          if (invalid_signon_realm) {
+            if (is_blacklisted || http_state.is_matching ||
+                https_state.is_matching)
+              expected_operation = ExpectedOperation::kDelete;
+            else
+              expected_operation = ExpectedOperation::kFix;
+          }
+          cases.push_back({is_blacklisted, invalid_signon_realm, http_state,
+                           https_state, expected_operation});
+        }
+      }
+    }
+  }
+
+  for (const TestCase& test : cases) {
+    SCOPED_TRACE(testing::Message()
+                 << "is_blacklisted=" << test.is_blacklisted
+                 << ", invalid_signon_realm=" << test.invalid_signon_realm
+                 << ", http_match=" << test.http_state.is_matching
+                 << ", http_same_username=" << test.http_state.same_username
+                 << ", http_same_creation_time="
+                 << test.http_state.same_creation_time
+                 << ", http_same_origin=" << test.http_state.same_origin
+                 << ", https_match=" << test.https_state.is_matching
+                 << ", https_same_signon_realm="
+                 << test.https_state.same_signon_realm
+                 << ", https_ssame_username=" << test.https_state.same_username
+                 << ", expected_operation="
+                 << static_cast<int>(test.expected_operation));
+
+    base::test::ScopedTaskEnvironment scoped_task_environment;
+    auto password_store = base::MakeRefCounted<TestPasswordStore>();
+    ASSERT_TRUE(password_store->Init(syncer::SyncableService::StartSyncFlare(),
+                                     nullptr));
+
+    const auto migration_pair = GetCredentialsFrom(
+        test.is_blacklisted, test.invalid_signon_realm, test.http_state);
+
+    // |https_form| is the form to be tested.
+    const autofill::PasswordForm& http_form_to_match = migration_pair.http_form;
+    const autofill::PasswordForm& https_form =
+        migration_pair.migrated_https_form;
+
+    autofill::PasswordForm https_form_to_match = https_form;
+    // |https_form| have one of kOrigins[0] or kOrigins[1].
+    // If we don't want to match |https_form| with |https_form_to_match| by
+    // web origin then we can simply use kOrigins[2].
+    if (!test.https_state.same_signon_realm) {
+      https_form_to_match.origin = kOrigins[2];
+    } else {
+      // Make |https_form| and |https_form_to_match| to have different unique
+      // key.
+      https_form_to_match.origin =
+          GURL(https_form_to_match.origin.spec() + "/different/");
+    }
+
+    // Make sure that HTTPS credentials we want to match with have valid
+    // signon_realm.
+    https_form_to_match.signon_realm =
+        https_form_to_match.origin.GetOrigin().spec();
+
+    if (!test.https_state.same_username)
+      https_form_to_match.username_value += base::ASCIIToUTF16("different");
+    // Even if |https_form| and |https_form_to_match| have the same signon_realm
+    // and username, they have to be created at different date of creation to
+    // simulate the real behavior when user manually adds credentials for the
+    // website.
+    https_form_to_match.date_created = kDates[2];
+
+    password_store->AddLogin(http_form_to_match);
+    password_store->AddLogin(https_form);
+    // The store will save |https_form| twice if it is equals with
+    // |https_form_to_match|.
+    password_store->AddLogin(https_form_to_match);
+
+    scoped_task_environment.RunUntilIdle();
+    // Check that all credentials were successfully added.
+    ASSERT_TRUE(StoreContains(password_store.get(), http_form_to_match));
+    ASSERT_TRUE(StoreContains(password_store.get(), https_form));
+    ASSERT_TRUE(StoreContains(password_store.get(), https_form_to_match));
+
+    TestingPrefServiceSimple prefs;
+    // Prevent cleaning of duplicated blacklist entries.
+    prefs.registry()->RegisterBooleanPref(
+        prefs::kDuplicatedBlacklistedCredentialsRemoved, true);
+    prefs.registry()->RegisterBooleanPref(
+        prefs::kCredentialsWithWrongSignonRealmRemoved, false);
+
+    password_manager_util::RemoveUselessCredentials(password_store, &prefs, 0);
+    scoped_task_environment.RunUntilIdle();
+
+    EXPECT_EQ(StoreContains(password_store.get(), https_form),
+              (test.expected_operation == ExpectedOperation::kNothing));
+
+    autofill::PasswordForm https_form_fixed = https_form;
+    https_form_fixed.signon_realm = https_form_fixed.origin.GetOrigin().spec();
+    // Check that they are fixed only when we expect them to be fixed.
+    EXPECT_EQ(StoreContains(password_store.get(), https_form_fixed),
+              !test.invalid_signon_realm ||
+                  (test.expected_operation == ExpectedOperation::kFix));
+    EXPECT_TRUE(
+        prefs.GetBoolean(prefs::kCredentialsWithWrongSignonRealmRemoved));
+
+    // HTTP form and valid HTTPS form have to stay untouched.
+    EXPECT_TRUE(StoreContains(password_store.get(), http_form_to_match));
+    EXPECT_TRUE(StoreContains(password_store.get(), https_form_to_match));
+
+    password_store->ShutdownOnUIThread();
+    scoped_task_environment.RunUntilIdle();
+  }
+}
+
+// This test checks that non-HTML credentials with invalid signon_realm are
+// correctly deleted.
+TEST(InvalidRealmCredentialCleanerTest,
+     RemoveNonHtmlCredentialsWithWrongSignonRealm) {
+  static constexpr struct SignonRealmState {
+    // Indicates whether HTTPS credentials were faulty migrated (the
+    // signon_realm contains the whole URL).
+    bool invalid_signon_realm;
+
+    // Indicates whether HTTP credentials which will be matched with HTTPS
+    // credentials had empty auth realm.
+    bool http_empty_realm;
+
+    // Indicates whether HTTPS credentials which were migrated have empty auth
+    // realm. If |invalid_signon_realm| is true then |https_empty_realm| should
+    // also be true.
+    bool https_empty_realm;
+
+    // Indicates whether signon_realms (excluding their protocol) of HTTP
+    // credentials and migrated HTTPS credentials are matching.
+    bool matching_signon_realm;
+  } kSignonRealmStates[]{
+      {false, false, false, true},
+      {false, false, true, false},
+      {false, true, false, false},
+      {false, true, true, true},
+      // For the next test matching_signon_realm is not
+      // set true because invalid_signon_realm means that
+      // HTTPS credentials will consists of the whole URL
+      // which is different by HTTP signon_realm (excluding protocol).
+      {true, true, true, false},
+      {true, false, true, false}};
+
+  struct TestCase {
+    bool is_blacklisted;
+    HttpMatchState http_state;
+    SignonRealmState signon_realm_state;
+    bool delete_expected;
+  };
+
+  std::vector<TestCase> cases;
+  for (bool is_blacklisted : {true, false}) {
+    for (const HttpMatchState& http_state : kHttpMatchStates) {
+      for (const SignonRealmState& signon_realm_state : kSignonRealmStates) {
+        // This state is invalid because blacklisted credentials has username
+        // cleared.
+        if (is_blacklisted && !http_state.same_username)
+          continue;
+        // This state is invalid because if the signon_realm is valid and there
+        // is a matching HTTP credential means that the migration was
+        // successful. So, signon_realms should be the same. If they are not,
+        // then state is invalid.
+        if (!signon_realm_state.invalid_signon_realm &&
+            http_state.is_matching && !signon_realm_state.matching_signon_realm)
+          continue;
+        cases.push_back({is_blacklisted, http_state, signon_realm_state,
+                         signon_realm_state.invalid_signon_realm &
+                             http_state.is_matching &
+                             !signon_realm_state.matching_signon_realm});
+      }
+    }
+  }
+
+  for (const TestCase& test : cases) {
+    SCOPED_TRACE(
+        testing::Message()
+        << "is_blacklisted=" << test.is_blacklisted
+        << ", http_empty_realm=" << test.signon_realm_state.http_empty_realm
+        << ", https_empty_realm=" << test.signon_realm_state.https_empty_realm
+        << ", invalid_signon_realm="
+        << test.signon_realm_state.invalid_signon_realm
+        << ", same_creation_time=" << test.http_state.same_creation_time
+        << ", same_origin=" << test.http_state.same_origin
+        << ", same_username=" << test.http_state.same_username
+        << ", delete_expected=" << test.delete_expected);
+    base::test::ScopedTaskEnvironment scoped_task_environment;
+    auto password_store = base::MakeRefCounted<TestPasswordStore>();
+    ASSERT_TRUE(password_store->Init(syncer::SyncableService::StartSyncFlare(),
+                                     nullptr));
+
+    auto migration_pair = GetCredentialsFrom(
+        test.is_blacklisted, test.signon_realm_state.invalid_signon_realm,
+        test.http_state);
+    autofill::PasswordForm& http_form = migration_pair.http_form;
+    autofill::PasswordForm& https_form = migration_pair.migrated_https_form;
+
+    http_form.scheme = autofill::PasswordForm::SCHEME_BASIC;
+    https_form.scheme = autofill::PasswordForm::SCHEME_BASIC;
+
+    // If the signon_realm is invalid that means the auth realm is empty.
+    if (test.signon_realm_state.invalid_signon_realm) {
+      ASSERT_TRUE(test.signon_realm_state.https_empty_realm);
+    }
+    if (!test.signon_realm_state.http_empty_realm) {
+      http_form.signon_realm += "realm";
+    }
+    if (!test.signon_realm_state.https_empty_realm) {
+      https_form.signon_realm += "realm";
+    }
+
+    password_store->AddLogin(http_form);
+    password_store->AddLogin(https_form);
+
+    scoped_task_environment.RunUntilIdle();
+    // Check that credentials were successfully added.
+    ASSERT_TRUE(StoreContains(password_store.get(), http_form));
+    ASSERT_TRUE(StoreContains(password_store.get(), https_form));
+
+    TestingPrefServiceSimple prefs;
+    // Prevent cleaning of duplicated blacklist entries.
+    prefs.registry()->RegisterBooleanPref(
+        prefs::kDuplicatedBlacklistedCredentialsRemoved, true);
+    prefs.registry()->RegisterBooleanPref(
+        prefs::kCredentialsWithWrongSignonRealmRemoved, false);
+
+    password_manager_util::RemoveUselessCredentials(password_store, &prefs, 0);
+    scoped_task_environment.RunUntilIdle();
+
+    EXPECT_NE(StoreContains(password_store.get(), https_form),
+              test.delete_expected);
+    EXPECT_TRUE(StoreContains(password_store.get(), http_form));
+    EXPECT_TRUE(
+        prefs.GetBoolean(prefs::kCredentialsWithWrongSignonRealmRemoved));
+
+    password_store->ShutdownOnUIThread();
+    scoped_task_environment.RunUntilIdle();
+  }
+}
+
+// This test checks that credentials that are not HTTP or HTTPS will be
+// untouched by the cleaning.
+TEST(InvalidRealmCredentialCleanerTest,
+     NotHttpAndHttpsCredentialsAreNotRemoved) {
+  base::test::ScopedTaskEnvironment scoped_task_environment;
+  auto password_store = base::MakeRefCounted<TestPasswordStore>();
+  ASSERT_TRUE(
+      password_store->Init(syncer::SyncableService::StartSyncFlare(), nullptr));
+
+  autofill::PasswordForm file_url;
+  file_url.origin = GURL("file://something.html");
+  password_store->AddLogin(file_url);
+
+  autofill::PasswordForm ftp_url;
+  ftp_url.origin = GURL("ftp://ftp.funet.fi/fc959.txt");
+  password_store->AddLogin(ftp_url);
+
+  scoped_task_environment.RunUntilIdle();
+  TestingPrefServiceSimple prefs;
+  // Prevent cleaning of duplicated blacklist entries.
+  prefs.registry()->RegisterBooleanPref(
+      prefs::kDuplicatedBlacklistedCredentialsRemoved, true);
+  prefs.registry()->RegisterBooleanPref(
+      prefs::kCredentialsWithWrongSignonRealmRemoved, false);
+
+  password_manager_util::RemoveUselessCredentials(password_store, &prefs, 0);
+  scoped_task_environment.RunUntilIdle();
+
+  // Check that credentials were not deleted.
+  ASSERT_TRUE(StoreContains(password_store.get(), file_url));
+  ASSERT_TRUE(StoreContains(password_store.get(), ftp_url));
+
+  password_store->ShutdownOnUIThread();
+  scoped_task_environment.RunUntilIdle();
+}
+
+}  // namespace password_manager
\ No newline at end of file
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index cfdaf594..89575227 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -281,6 +281,9 @@
       user_prefs::PrefRegistrySyncable::SYNCABLE_PRIORITY_PREF);
   registry->RegisterBooleanPref(prefs::kDuplicatedBlacklistedCredentialsRemoved,
                                 false);
+  registry->RegisterBooleanPref(prefs::kCredentialsWithWrongSignonRealmRemoved,
+                                false);
+
 #if defined(OS_MACOSX)
   registry->RegisterIntegerPref(
       prefs::kKeychainMigrationStatus,
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc
index 96990ac..639fc0f 100644
--- a/components/password_manager/core/browser/password_manager_util.cc
+++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -20,6 +20,7 @@
 #include "components/password_manager/core/browser/credentials_cleaner.h"
 #include "components/password_manager/core/browser/credentials_cleaner_runner.h"
 #include "components/password_manager/core/browser/hsts_query.h"
+#include "components/password_manager/core/browser/invalid_realm_credential_cleaner.h"
 #include "components/password_manager/core/browser/log_manager.h"
 #include "components/password_manager/core/browser/password_generation_manager.h"
 #include "components/password_manager/core/browser/password_manager.h"
@@ -337,20 +338,39 @@
       autofill::password_generation::PASSWORD_GENERATION_CONTEXT_MENU_PRESSED);
 }
 
-void DeleteBlacklistedDuplicates(
+void RemoveUselessCredentials(
     scoped_refptr<password_manager::PasswordStore> store,
     PrefService* prefs,
     int delay_in_seconds) {
+  // TODO(https://crbug.com/887889): Remove the knowledge of the particular
+  // preferences from this code.
+
   const bool need_to_remove_blacklisted_duplicates = !prefs->GetBoolean(
       password_manager::prefs::kDuplicatedBlacklistedCredentialsRemoved);
   base::UmaHistogramBoolean(
       "PasswordManager.BlacklistedSites.NeedRemoveBlacklistDuplicates",
       need_to_remove_blacklisted_duplicates);
 
+  const bool need_to_remove_invalid_credentials = !prefs->GetBoolean(
+      password_manager::prefs::kCredentialsWithWrongSignonRealmRemoved);
+  base::UmaHistogramBoolean(
+      "PasswordManager.InvalidtHttpsCredentialsNeedToBeCleared",
+      need_to_remove_invalid_credentials);
+
   // The object will delete itself once the clearing tasks are done.
   auto* cleaning_tasks_runner =
       new password_manager::CredentialsCleanerRunner();
 
+  // Cleaning of credentials with invalid signon_realm needs to search for
+  // blacklisted non-HTML HTTPS credentials for a corresponding HTTP
+  // credentials. Thus, this clean-up must be done before cleaning blacklisted
+  // credentials. Otherwise finding a corresponding HTTP credentials will fail.
+  if (need_to_remove_invalid_credentials) {
+    cleaning_tasks_runner->AddCleaningTask(
+        std::make_unique<password_manager::InvalidRealmCredentialCleaner>(
+            store, prefs));
+  }
+
   if (need_to_remove_blacklisted_duplicates) {
     cleaning_tasks_runner->AddCleaningTask(
         std::make_unique<password_manager::BlacklistedDuplicatesCleaner>(
diff --git a/components/password_manager/core/browser/password_manager_util.h b/components/password_manager/core/browser/password_manager_util.h
index c6912f5..cb80509a 100644
--- a/components/password_manager/core/browser/password_manager_util.h
+++ b/components/password_manager/core/browser/password_manager_util.h
@@ -92,9 +92,15 @@
 void UserTriggeredManualGenerationFromContextMenu(
     password_manager::PasswordManagerClient* password_manager_client);
 
-// Two blacklisted forms are considered equal if they have the same
-// signon_realm.
-void DeleteBlacklistedDuplicates(
+// This function handles the following clean-ups of credentials:
+// (1) Removing blacklisted duplicates: if two blacklisted credentials have the
+// same signon_realm, they are duplicates of each other. Deleting all but one
+// sharing the signon_realm does not affect Chrome's behaviour and hence
+// duplicates can be removed. Having duplicates makes un-blacklisting not work,
+// hence blacklisted duplicates need to be removed.
+// (2) Removing or fixing of HTTPS credentials with wrong signon_realm. See
+// https://crbug.com/881731 for details.
+void RemoveUselessCredentials(
     scoped_refptr<password_manager::PasswordStore> store,
     PrefService* prefs,
     int delay_in_seconds);
diff --git a/components/password_manager/core/browser/password_manager_util_unittest.cc b/components/password_manager/core/browser/password_manager_util_unittest.cc
index 832f064..b49c280 100644
--- a/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -5,6 +5,7 @@
 #include "components/password_manager/core/browser/password_manager_util.h"
 
 #include <memory>
+#include <string>
 #include <utility>
 #include <vector>
 
@@ -20,6 +21,8 @@
 #include "components/password_manager/core/browser/password_manager_test_utils.h"
 #include "components/password_manager/core/browser/test_password_store.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
 #include "net/url_request/url_request_test_util.h"
 #include "services/network/network_context.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -45,6 +48,13 @@
   return form;
 }
 
+bool StoreContains(password_manager::TestPasswordStore* store,
+                   const autofill::PasswordForm& form) {
+  const auto it = store->stored_passwords().find(form.signon_realm);
+  return it != store->stored_passwords().end() &&
+         base::ContainsValue(it->second, form);
+}
+
 // The argument is std::vector<autofill::PasswordForm*>*. The caller is
 // responsible for the lifetime of all the password forms.
 ACTION_P(AppendForm, form) {
@@ -259,6 +269,125 @@
 }
 #endif  // !defined(OS_IOS)
 
+// This test is supposed to check the behavior when:
+// 1. User blacklisted on http site two forms (they being considered
+// duplicated because they have the same signon_realm).
+// 2. They are faulty migrated, resulting in 2 blacklisted invalid credentials.
+// Check that both duplicated and invalid credentials are
+// correctly deleted.
+TEST(PasswordManagerUtil,
+     RemoveInvalidHttpsCredentialsAndBlacklistedDuplicates) {
+  for (auto scheme : {autofill::PasswordForm::Scheme::SCHEME_HTML,
+                      autofill::PasswordForm::Scheme::SCHEME_BASIC}) {
+    SCOPED_TRACE(testing::Message() << "scheme=" << static_cast<int>(scheme));
+
+    base::test::ScopedTaskEnvironment scoped_task_environment;
+    auto password_store =
+        base::MakeRefCounted<password_manager::TestPasswordStore>();
+    ASSERT_TRUE(password_store->Init(syncer::SyncableService::StartSyncFlare(),
+                                     nullptr));
+
+    autofill::PasswordForm http_blacklisted;
+    http_blacklisted.origin = GURL("http://example.com/something/");
+    http_blacklisted.signon_realm = "http://example.com/";
+    http_blacklisted.blacklisted_by_user = true;
+    http_blacklisted.date_created = base::Time::FromDoubleT(100);
+    http_blacklisted.scheme = scheme;
+    password_store->AddLogin(http_blacklisted);
+
+    // Duplicate version of |http_blacklisted|.
+    autofill::PasswordForm http_blacklisted_duplicate;
+    http_blacklisted_duplicate.origin = GURL("http://example.com/something-2/");
+    http_blacklisted_duplicate.signon_realm = "http://example.com/";
+    http_blacklisted_duplicate.blacklisted_by_user = true;
+    http_blacklisted_duplicate.date_created = base::Time::FromDoubleT(200);
+    http_blacklisted_duplicate.scheme = scheme;
+    password_store->AddLogin(http_blacklisted_duplicate);
+
+    // Migrated version of |http_blacklisted|.
+    autofill::PasswordForm invalid_blacklisted = http_blacklisted;
+    invalid_blacklisted.origin = GURL("https://example.com/something/");
+    invalid_blacklisted.signon_realm = "https://example.com/something/";
+    password_store->AddLogin(invalid_blacklisted);
+
+    // Migrated version of |http_blacklisted_duplicate|.
+    autofill::PasswordForm invalid_blacklisted_duplicate =
+        http_blacklisted_duplicate;
+    invalid_blacklisted_duplicate.origin =
+        GURL("https://example.com/something-2/");
+    invalid_blacklisted_duplicate.signon_realm =
+        "https://example.com/something-2/";
+    password_store->AddLogin(invalid_blacklisted_duplicate);
+
+    // These credentials have to be untouched by cleaning of invalid https but
+    // one of them has to be removed by function that removes blacklisted
+    // duplicates.
+    autofill::PasswordForm https_blacklisted;
+    https_blacklisted.blacklisted_by_user = true;
+    https_blacklisted.origin = GURL("https://google.com/something/");
+    https_blacklisted.signon_realm = "https://google.com/";
+    https_blacklisted.scheme = scheme;
+    password_store->AddLogin(https_blacklisted);
+
+    autofill::PasswordForm https_blacklisted_duplicate = https_blacklisted;
+    https_blacklisted_duplicate.origin =
+        GURL("https://google.com/something-2/");
+    https_blacklisted_duplicate.signon_realm = "https://google.com/";
+    password_store->AddLogin(https_blacklisted_duplicate);
+
+    scoped_task_environment.RunUntilIdle();
+    // Check that all credentials were successfully added.
+    ASSERT_TRUE(StoreContains(password_store.get(), http_blacklisted));
+    ASSERT_TRUE(
+        StoreContains(password_store.get(), http_blacklisted_duplicate));
+    ASSERT_TRUE(StoreContains(password_store.get(), invalid_blacklisted));
+    ASSERT_TRUE(
+        StoreContains(password_store.get(), invalid_blacklisted_duplicate));
+    ASSERT_TRUE(StoreContains(password_store.get(), https_blacklisted));
+    ASSERT_TRUE(
+        StoreContains(password_store.get(), https_blacklisted_duplicate));
+
+    TestingPrefServiceSimple prefs;
+    prefs.registry()->RegisterBooleanPref(
+        password_manager::prefs::kDuplicatedBlacklistedCredentialsRemoved,
+        false);
+
+    prefs.registry()->RegisterBooleanPref(
+        password_manager::prefs::kCredentialsWithWrongSignonRealmRemoved,
+        false);
+
+    RemoveUselessCredentials(password_store, &prefs, 0);
+    scoped_task_environment.RunUntilIdle();
+
+    // Check that invalid credentials were removed.
+    EXPECT_FALSE(StoreContains(password_store.get(), invalid_blacklisted));
+    EXPECT_FALSE(
+        StoreContains(password_store.get(), invalid_blacklisted_duplicate));
+
+    // One of them has to be removed.
+    EXPECT_NE(StoreContains(password_store.get(), http_blacklisted),
+              StoreContains(password_store.get(), http_blacklisted_duplicate));
+    // One of them has to be removed.
+    EXPECT_NE(StoreContains(password_store.get(), https_blacklisted),
+              StoreContains(password_store.get(), https_blacklisted_duplicate));
+
+    RemoveUselessCredentials(password_store, &prefs, 0);
+    scoped_task_environment.RunUntilIdle();
+
+    // Nothing must be removed by a second call.
+    EXPECT_FALSE(StoreContains(password_store.get(), invalid_blacklisted));
+    EXPECT_FALSE(
+        StoreContains(password_store.get(), invalid_blacklisted_duplicate));
+    EXPECT_NE(StoreContains(password_store.get(), http_blacklisted),
+              StoreContains(password_store.get(), http_blacklisted_duplicate));
+    EXPECT_NE(StoreContains(password_store.get(), https_blacklisted),
+              StoreContains(password_store.get(), https_blacklisted_duplicate));
+
+    password_store->ShutdownOnUIThread();
+    scoped_task_environment.RunUntilIdle();
+  }
+}
+
 TEST(PasswordManagerUtil, FindBestMatches) {
   const int kNotFound = -1;
   struct TestMatch {
diff --git a/components/password_manager/core/common/password_manager_pref_names.cc b/components/password_manager/core/common/password_manager_pref_names.cc
index a54e88e..9a99340b 100644
--- a/components/password_manager/core/common/password_manager_pref_names.cc
+++ b/components/password_manager/core/common/password_manager_pref_names.cc
@@ -44,6 +44,9 @@
 const char kDuplicatedBlacklistedCredentialsRemoved[] =
     "profile.duplicated_blacklisted_credentials_removed";
 
+const char kCredentialsWithWrongSignonRealmRemoved[] =
+    "profile.credentials_with_wrong_signon_realm_removed";
+
 const char kPasswordHashDataList[] = "profile.password_hash_data_list";
 
 }  // namespace prefs
diff --git a/components/password_manager/core/common/password_manager_pref_names.h b/components/password_manager/core/common/password_manager_pref_names.h
index 5209543..a978d6e7 100644
--- a/components/password_manager/core/common/password_manager_pref_names.h
+++ b/components/password_manager/core/common/password_manager_pref_names.h
@@ -73,6 +73,9 @@
 // Whether Chrome deleted blacklisted credentials that were duplicated.
 extern const char kDuplicatedBlacklistedCredentialsRemoved[];
 
+// Whether Chrome deleted credentials that had wrong signon_realm.
+extern const char kCredentialsWithWrongSignonRealmRemoved[];
+
 // List that contains captured password hashes.
 extern const char kPasswordHashDataList[];
 
diff --git a/components/plugins/renderer/webview_plugin.cc b/components/plugins/renderer/webview_plugin.cc
index 79e01ec..0391266 100644
--- a/components/plugins/renderer/webview_plugin.cc
+++ b/components/plugins/renderer/webview_plugin.cc
@@ -262,7 +262,7 @@
   content::RenderView::ApplyWebPreferences(preferences, web_view_);
   WebLocalFrame* web_frame =
       WebLocalFrame::CreateMainFrame(web_view_, this, nullptr, nullptr);
-  WebFrameWidget::Create(this, web_frame);
+  WebFrameWidget::CreateForMainFrame(this, web_frame);
 }
 
 WebViewPlugin::WebViewHelper::~WebViewHelper() {
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index fc7f0f5..26b88c1d 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -632,10 +632,6 @@
     blink::WebLocalFrame* frame_;
   };
 
-  HeaderAndFooterClient frame_client;
-  blink::WebLocalFrame* frame = blink::WebLocalFrame::CreateMainFrame(
-      web_view, &frame_client, nullptr, nullptr);
-
   class NonCompositingWebWidgetClient : public blink::WebWidgetClient {
    public:
     // blink::WebWidgetClient implementation.
@@ -645,8 +641,12 @@
     }
   };
 
+  HeaderAndFooterClient frame_client;
+  blink::WebLocalFrame* frame = blink::WebLocalFrame::CreateMainFrame(
+      web_view, &frame_client, nullptr, nullptr);
+
   NonCompositingWebWidgetClient web_widget_client;
-  blink::WebFrameWidget::Create(&web_widget_client, frame);
+  blink::WebFrameWidget::CreateForMainFrame(&web_widget_client, frame);
 
   base::Value html(ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
       IDR_PRINT_HEADER_FOOTER_TEMPLATE_PAGE));
@@ -876,7 +876,7 @@
   blink::WebLocalFrame* main_frame =
       blink::WebLocalFrame::CreateMainFrame(web_view, this, nullptr, nullptr);
   frame_.Reset(main_frame);
-  blink::WebFrameWidget::Create(this, main_frame);
+  blink::WebFrameWidget::CreateForMainFrame(this, main_frame);
   node_to_print_.Reset();
 
   // When loading is done this will call didStopLoading() and that will do the
diff --git a/components/safe_browsing/password_protection/BUILD.gn b/components/safe_browsing/password_protection/BUILD.gn
index c1d76c9..87b9e3f5 100644
--- a/components/safe_browsing/password_protection/BUILD.gn
+++ b/components/safe_browsing/password_protection/BUILD.gn
@@ -50,6 +50,7 @@
     "//base",
     "//components/safe_browsing:csd_proto",
     "//net:net",
+    "//ui/gfx/geometry:geometry",
   ]
 }
 
diff --git a/components/safe_browsing/password_protection/DEPS b/components/safe_browsing/password_protection/DEPS
index 0aea96dc..c305e06 100644
--- a/components/safe_browsing/password_protection/DEPS
+++ b/components/safe_browsing/password_protection/DEPS
@@ -9,5 +9,6 @@
   "+net",
   "+services/network/public",
   "+services/network/test",
+  "+ui/gfx/geometry",
 ]
 
diff --git a/components/safe_browsing/password_protection/metrics_util.cc b/components/safe_browsing/password_protection/metrics_util.cc
index 9f5655de..6e6bfa2 100644
--- a/components/safe_browsing/password_protection/metrics_util.cc
+++ b/components/safe_browsing/password_protection/metrics_util.cc
@@ -238,4 +238,11 @@
       reuse_count);
 }
 
+void LogContentsSize(const gfx::Size& size) {
+  if (size.width() <= 0 || size.height() <= 0)
+    return;
+  UMA_HISTOGRAM_COUNTS_10000("SafeBrowsing.ContentsSize.Width", size.width());
+  UMA_HISTOGRAM_COUNTS_10000("SafeBrowsing.ContentsSize.Height", size.height());
+}
+
 }  // namespace safe_browsing
diff --git a/components/safe_browsing/password_protection/metrics_util.h b/components/safe_browsing/password_protection/metrics_util.h
index 07577e8..4ffbc45 100644
--- a/components/safe_browsing/password_protection/metrics_util.h
+++ b/components/safe_browsing/password_protection/metrics_util.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "components/safe_browsing/proto/csd.pb.h"
+#include "ui/gfx/geometry/size.h"
 
 namespace base {
 class TimeTicks;
@@ -183,6 +184,9 @@
     LoginReputationClientResponse::VerdictType verdict_type,
     int referrer_chain_size);
 
+// Logs the content area size in DIPs.
+void LogContentsSize(const gfx::Size& size);
+
 }  // namespace safe_browsing
 
 #endif  // COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_METRICS_UTIL_H_
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index 7901ac0..ff07af8 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -409,10 +409,23 @@
 }
 
 void AccountReconcilor::FinishReconcileWithMultiloginEndpoint(
-    const std::vector<gaia::ListedAccount>& gaia_accounts) {
+    const std::string& primary_account,
+    const std::vector<std::string>& chrome_accounts,
+    std::vector<gaia::ListedAccount>&& gaia_accounts) {
   DCHECK(base::FeatureList::IsEnabled(kUseMultiloginEndpoint));
-  NOTIMPLEMENTED();
-  // TODO(valeriyas): implement.
+
+  std::vector<std::string> accounts_to_send;
+  if (delegate_->ReorderChromeAccountsForReconcileIfNeeded(
+          chrome_accounts, primary_account, gaia_accounts, &accounts_to_send)) {
+    PerformSetCookiesAction(accounts_to_send);
+  } else {
+    OnSetAccountsInCookieCompleted(GoogleServiceAuthError::AuthErrorNone());
+  }
+  // TODO(valeriyas): Log operation here.
+  if (!is_reconcile_started_)
+    delegate_->OnReconcileFinished(gaia_accounts[0].id, reconcile_is_noop_);
+  first_execution_ = false;
+  ScheduleStartReconcileIfChromeAccountsChanged();
 }
 
 void AccountReconcilor::OnGaiaAccountsInCookieUpdated(
@@ -467,7 +480,9 @@
   }
 
   if (base::FeatureList::IsEnabled(kUseMultiloginEndpoint)) {
-    FinishReconcileWithMultiloginEndpoint(std::move(verified_gaia_accounts));
+    FinishReconcileWithMultiloginEndpoint(primary_account,
+                                          LoadValidAccountsFromTokenService(),
+                                          std::move(verified_gaia_accounts));
   } else {
     FinishReconcile(primary_account, LoadValidAccountsFromTokenService(),
                     std::move(verified_gaia_accounts));
@@ -684,8 +699,15 @@
     if (error.state() != GoogleServiceAuthError::State::NONE &&
         !error_during_last_reconcile_.IsPersistentError()) {
       error_during_last_reconcile_ = error;
+      delegate_->OnReconcileError(error_during_last_reconcile_);
     }
-    CalculateIfReconcileIsDone();
+    is_reconcile_started_ = false;
+
+    timer_->Stop();
+    base::TimeDelta duration = base::Time::Now() - reconcile_start_time_;
+    signin_metrics::LogSigninAccountReconciliationDuration(
+        duration, (error_during_last_reconcile_.state() ==
+                   GoogleServiceAuthError::State::NONE));
     ScheduleStartReconcileIfChromeAccountsChanged();
   }
 }
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h
index 3a7b8e1..af197e7 100644
--- a/components/signin/core/browser/account_reconcilor.h
+++ b/components/signin/core/browser/account_reconcilor.h
@@ -115,10 +115,13 @@
   friend class Lock;
   friend class AccountReconcilorTest;
   friend class DiceBrowserTestBase;
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, SigninManagerRegistration);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, Reauth);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, ProfileAlreadyConnected);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestDice, TableRowTest);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           SigninManagerRegistration);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, Reauth);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           ProfileAlreadyConnected);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestTable, TableRowTest);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTestMirrorMultilogin, TableRowTest);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DiceTokenServiceRegistration);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DiceReconcileWhithoutSignin);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DiceReconcileNoop);
@@ -136,41 +139,55 @@
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
                            MigrationClearSecondaryTokens);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, MigrationClearAllTokens);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, TokensNotLoaded);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           TokensNotLoaded);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
                            StartReconcileCookiesDisabled);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
                            StartReconcileContentSettings);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
                            StartReconcileContentSettingsGaiaUrl);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
                            StartReconcileContentSettingsNonGaiaUrl);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
                            StartReconcileContentSettingsInvalidPattern);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, GetAccountsFromCookieSuccess);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, GetAccountsFromCookieFailure);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoop);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoopWithDots);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoopMultiple);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileAddToCookie);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           GetAccountsFromCookieSuccess);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           GetAccountsFromCookieFailure);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           StartReconcileNoop);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           StartReconcileNoopWithDots);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           StartReconcileNoopMultiple);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           StartReconcileAddToCookie);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, AuthErrorTriggersListAccount);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
                            SignoutAfterErrorDoesNotRecordUma);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           TokenErrorOnPrimary);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
                            StartReconcileRemoveFromCookie);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
                            StartReconcileAddToCookieTwice);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileBadPrimary);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileOnlyOnce);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, Lock);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           StartReconcileBadPrimary);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           StartReconcileOnlyOnce);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest, Lock);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMethodParamTest,
                            StartReconcileWithSessionInfoExpiredDefault);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
                            AddAccountToCookieCompletedWithBogusAccount);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, NoLoopWithBadPrimary);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, WontMergeAccountsWithError);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           NoLoopWithBadPrimary);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           WontMergeAccountsWithError);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DelegateTimeoutIsCalled);
-  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, DelegateTimeoutIsNotCalled);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMirrorEndpointParamTest,
+                           DelegateTimeoutIsNotCalled);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
                            DelegateTimeoutIsNotCalledIfTimeoutIsNotReached);
 
@@ -240,7 +257,9 @@
                           const GoogleServiceAuthError& error) override;
 
   void FinishReconcileWithMultiloginEndpoint(
-      const std::vector<gaia::ListedAccount>& gaia_accounts);
+      const std::string& primary_account,
+      const std::vector<std::string>& chrome_accounts,
+      std::vector<gaia::ListedAccount>&& gaia_accounts);
 
   // Lock related methods.
   void IncrementLockCount();
diff --git a/components/signin/core/browser/account_reconcilor_delegate.cc b/components/signin/core/browser/account_reconcilor_delegate.cc
index 867040f4..334667a 100644
--- a/components/signin/core/browser/account_reconcilor_delegate.cc
+++ b/components/signin/core/browser/account_reconcilor_delegate.cc
@@ -36,6 +36,14 @@
   return std::string();
 }
 
+bool AccountReconcilorDelegate::ReorderChromeAccountsForReconcileIfNeeded(
+    const std::vector<std::string>& chrome_accounts,
+    const std::string primary_account,
+    const std::vector<gaia::ListedAccount>& gaia_accounts,
+    std::vector<std::string>* accounts_to_send) const {
+  return false;
+}
+
 AccountReconcilorDelegate::RevokeTokenOption
 AccountReconcilorDelegate::ShouldRevokeSecondaryTokensBeforeReconcile(
     const std::vector<gaia::ListedAccount>& gaia_accounts) {
diff --git a/components/signin/core/browser/account_reconcilor_delegate.h b/components/signin/core/browser/account_reconcilor_delegate.h
index d4bdd20..1e4d994 100644
--- a/components/signin/core/browser/account_reconcilor_delegate.h
+++ b/components/signin/core/browser/account_reconcilor_delegate.h
@@ -61,6 +61,16 @@
       bool first_execution,
       bool will_logout) const;
 
+  // Reorders chrome accounts in the order they should appear in cookies with
+  // respect to existing cookies. Returns true if the resulting vector is not
+  // the same as existing vector of gaia accounts (i.e. cookies should be
+  // rebuilt).
+  virtual bool ReorderChromeAccountsForReconcileIfNeeded(
+      const std::vector<std::string>& chrome_accounts,
+      const std::string primary_account,
+      const std::vector<gaia::ListedAccount>& gaia_accounts,
+      std::vector<std::string>* accounts_to_send) const;
+
   // Returns whether secondary accounts should be cleared at the beginning of
   // the reconcile.
   virtual RevokeTokenOption ShouldRevokeSecondaryTokensBeforeReconcile(
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc
index 5d2756b6..91ec30c 100644
--- a/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/scoped_observer.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
 #include "base/time/time.h"
 #include "base/timer/mock_timer.h"
 #include "build/build_config.h"
@@ -193,6 +194,8 @@
 
   MOCK_METHOD1(PerformMergeAction, void(const std::string& account_id));
   MOCK_METHOD0(PerformLogoutAllAccountsAction, void());
+  MOCK_METHOD1(PerformSetCookiesAction,
+               void(const std::vector<std::string>& account_id));
 };
 
 MockAccountReconcilor::MockAccountReconcilor(
@@ -256,6 +259,10 @@
       content_settings::Observer* observer,
       const ContentSettingsPattern& primary_pattern);
 
+  void SimulateSetAccountsInCookieCompleted(
+      GaiaCookieManagerService::Observer* observer,
+      const GoogleServiceAuthError& error);
+
   GURL get_check_connection_info_url() {
     return get_check_connection_info_url_;
   }
@@ -280,6 +287,25 @@
   DISALLOW_COPY_AND_ASSIGN(AccountReconcilorTest);
 };
 
+class AccountReconcilorMirrorEndpointParamTest
+    : public AccountReconcilorTest,
+      public ::testing::WithParamInterface<bool> {
+ public:
+  AccountReconcilorMirrorEndpointParamTest() = default;
+
+  void SetUp() override {
+    SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+    if (GetParam())
+      scoped_feature_list_.InitAndEnableFeature(kUseMultiloginEndpoint);
+  }
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AccountReconcilorMirrorEndpointParamTest);
+};
+
 // For tests that must be run with multiple account consistency methods.
 class AccountReconcilorMethodParamTest
     : public AccountReconcilorTest,
@@ -386,6 +412,12 @@
   observer->OnAddAccountToCookieCompleted(account_id, error);
 }
 
+void AccountReconcilorTest::SimulateSetAccountsInCookieCompleted(
+    GaiaCookieManagerService::Observer* observer,
+    const GoogleServiceAuthError& error) {
+  observer->OnSetAccountsInCookieCompleted(error);
+}
+
 void AccountReconcilorTest::SimulateCookieContentSettingsChanged(
     content_settings::Observer* observer,
     const ContentSettingsPattern& primary_pattern) {
@@ -404,244 +436,51 @@
   ASSERT_TRUE(reconcilor);
 }
 
-#if !defined(OS_CHROMEOS)
+enum class IsFirstReconcile {
+  kBoth = 0,
+  kFirst,
+  kNotFirst,
+};
 
-// This method requires the use of the |TestSigninClient| to be created from the
-// |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded|
-// method with an empty implementation. On MacOS, the normal implementation
-// causes the try_bots to time out.
-TEST_F(AccountReconcilorTest, SigninManagerRegistration) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
-  AccountReconcilor* reconcilor = GetMockReconcilor();
-  ASSERT_TRUE(reconcilor);
-  ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService());
-
-  account_tracker()->SeedAccountInfo("12345", "user@gmail.com");
-  signin_manager()->SignIn("12345", "user@gmail.com", "password");
-  ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
-
-  EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
-
-  signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
-                            signin_metrics::SignoutDelete::IGNORE_METRIC);
-  ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService());
-}
-
-// This method requires the use of the |TestSigninClient| to be created from the
-// |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded|
-// method with an empty implementation. On MacOS, the normal implementation
-// causes the try_bots to time out.
-TEST_F(AccountReconcilorTest, Reauth) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
-  const std::string email = "user@gmail.com";
-  const std::string account_id = ConnectProfileToAccount("12345", email);
-
-  AccountReconcilor* reconcilor = GetMockReconcilor();
-  ASSERT_TRUE(reconcilor);
-  ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
-
-  // Simulate reauth.  The state of the reconcilor should not change.
-  signin_manager()->OnExternalSigninCompleted(email);
-  ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
-}
-
-#endif  // !defined(OS_CHROMEOS)
-
-TEST_F(AccountReconcilorTest, ProfileAlreadyConnected) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
-  ConnectProfileToAccount("12345", "user@gmail.com");
-
-  AccountReconcilor* reconcilor = GetMockReconcilor();
-  ASSERT_TRUE(reconcilor);
-  ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
-}
-
-#if BUILDFLAG(ENABLE_DICE_SUPPORT)
-
-struct AccountReconcilorTestDiceParam {
+struct AccountReconcilorTestTableParam {
   const char* tokens;
   const char* cookies;
-  bool is_first_reconcile;
+  IsFirstReconcile is_first_reconcile;
   const char* gaia_api_calls;
   const char* tokens_after_reconcile;
   const char* cookies_after_reconcile;
 };
 
-// Pretty prints a AccountReconcilorTestDiceParam. Used by gtest.
-void PrintTo(const AccountReconcilorTestDiceParam& param, ::std::ostream* os) {
-  *os << "Tokens: " << param.tokens << ". Cookies: " << param.cookies
-      << ". First reconcile: " << param.is_first_reconcile;
+std::vector<AccountReconcilorTestTableParam> GenerateTestCasesFromParams(
+    const std::vector<AccountReconcilorTestTableParam>& params) {
+  std::vector<AccountReconcilorTestTableParam> return_params;
+  for (const AccountReconcilorTestTableParam& param : params) {
+    if (param.is_first_reconcile == IsFirstReconcile::kBoth) {
+      AccountReconcilorTestTableParam param_true = param;
+      param_true.is_first_reconcile = IsFirstReconcile::kFirst;
+      AccountReconcilorTestTableParam param_false = param;
+      param_false.is_first_reconcile = IsFirstReconcile::kNotFirst;
+      return_params.push_back(param_true);
+      return_params.push_back(param_false);
+    } else {
+      return_params.push_back(param);
+    }
+  }
+  return return_params;
 }
 
-// clang-format off
-const AccountReconcilorTestDiceParam kDiceParams[] = {
-    // This table encodes the initial state and expectations of a reconcile.
-    // The syntax is:
-    // - Tokens:
-    //   A, B, C: Accounts for which we have a token in Chrome.
-    //   *: The next account is the main Chrome account (i.e. in SigninManager).
-    //   x: The next account has a token error.
-    // - Cookies:
-    //   A, B, C: Accounts in the Gaia cookie (returned by ListAccounts).
-    //   x: The next cookie is marked "invalid".
-    // - First Run: true if this is the first reconcile (i.e. Chrome startup).
-    // - API calls:
-    //   X: Logout all accounts.
-    //   A, B, C: Merge account.
-    // -------------------------------------------------------------------------
-    // Tokens | Cookies | First Run | Gaia calls | Tokens after | Cookies after
-    // -------------------------------------------------------------------------
-
-    // First reconcile (Chrome restart): Rebuild the Gaia cookie to match the
-    // tokens. Make the Sync account the default account in the Gaia cookie.
-    // Sync enabled.
-    {  "*AB",   "AB",     true,       "",          "*AB",         "AB"},
-    {  "*AB",   "BA",     true,       "XAB",       "*AB",         "AB"},
-    {  "*AB",   "A",      true,       "B",         "*AB",         "AB"},
-    {  "*AB",   "B",      true,       "XAB",       "*AB",         "AB"},
-    {  "*AB",   "",       true,       "AB",        "*AB",         "AB"},
-    // Sync enabled, token error on primary.
-    {  "*xAB",  "AB",     true,       "X",         "*xA",         ""},
-    {  "*xAB",  "BA",     true,       "XB",        "*xAB",        "B"},
-    {  "*xAB",  "A",      true,       "X",         "*xA",         ""},
-    {  "*xAB",  "B",      true,       "",          "*xAB",        "B"},
-    {  "*xAB",  "",       true,       "B",         "*xAB",        "B"},
-    // Sync enabled, token error on secondary.
-    {  "*AxB",  "AB",     true,       "XA",        "*A",          "A"},
-    {  "*AxB",  "BA",     true,       "XA",        "*A",          "A"},
-    {  "*AxB",  "A",      true,       "",          "*A",          "A"},
-    {  "*AxB",  "B",      true,       "XA",        "*A",          "A"},
-    {  "*AxB",  "",       true,       "A",         "*A",          "A"},
-    // Sync enabled, token error on both accounts.
-    {  "*xAxB", "AB",     true,       "X",         "*xA",         ""},
-    {  "*xAxB", "BA",     true,       "X",         "*xA",         ""},
-    {  "*xAxB", "A",      true,       "X",         "*xA",         ""},
-    {  "*xAxB", "B",      true,       "X",         "*xA",         ""},
-    {  "*xAxB", "",       true,       "",          "*xA",         ""},
-    // Sync disabled.
-    {  "AB",    "AB",     true,       "",          "AB",          "AB"},
-    {  "AB",    "BA",     true,       "",          "AB",          "BA"},
-    {  "AB",    "A",      true,       "B",         "AB",          "AB"},
-    {  "AB",    "B",      true,       "A",         "AB",          "BA"},
-    {  "AB",    "",       true,       "AB",        "AB",          "AB"},
-    // Sync disabled, token error on first account.
-    {  "xAB",   "AB",     true,       "XB",        "B",           "B"},
-    {  "xAB",   "BA",     true,       "XB",        "B",           "B"},
-    {  "xAB",   "A",      true,       "XB",        "B",           "B"},
-    {  "xAB",   "B",      true,       "",          "B",           "B"},
-    {  "xAB",   "",       true,       "B",         "B",           "B"},
-    // Sync disabled, token error on second account       .
-    {  "AxB",   "AB",     true,       "XA",        "A",           "A"},
-    {  "AxB",   "BA",     true,       "XA",        "A",           "A"},
-    {  "AxB",   "A",      true,       "",          "A",           "A"},
-    {  "AxB",   "B",      true,       "XA",        "A",           "A"},
-    {  "AxB",   "",       true,       "A",         "A",           "A"},
-    // Sync disabled, token error on both accounts.
-    {  "xAxB",  "AB",     true,       "X",         "",            ""},
-    {  "xAxB",  "BA",     true,       "X",         "",            ""},
-    {  "xAxB",  "A",      true,       "X",         "",            ""},
-    {  "xAxB",  "B",      true,       "X",         "",            ""},
-    {  "xAxB",  "",       true,       "",          "",            ""},
-
-    // Chrome is running: Do not change the order of accounts already present in
-    // the Gaia cookies.
-    // Sync enabled.
-    {  "*AB",   "AB",     false,      "",          "*AB",         "AB"},
-    {  "*AB",   "BA",     false,      "",          "*AB",         "BA"},
-    {  "*AB",   "A",      false,      "B",         "*AB",         "AB"},
-    {  "*AB",   "B",      false,      "A",         "*AB",         "BA"},
-    {  "*AB",   "",       false,      "AB",        "*AB",         "AB"},
-    // Sync enabled, token error on primary.
-    {  "*xAB",  "AB",     false,      "X",         "*xA",         ""},
-    {  "*xAB",  "BA",     false,      "XB",        "*xAB",        "B"},
-    {  "*xAB",  "A",      false,      "X",         "*xA",         ""},
-    {  "*xAB",  "B",      false,      "",          "*xAB",        "B"},
-    {  "*xAB",  "",       false,      "B",         "*xAB",        "B"},
-    // Sync enabled, token error on secondary.
-    {  "*AxB",  "AB",     false,      "XA",        "*A",          "A"},
-    {  "*AxB",  "BA",     false,      "XA",        "*A",          "A"},
-    {  "*AxB",  "A",      false,      "",          "*A",          "A"},
-    {  "*AxB",  "B",      false,      "XA",        "*A",          "A"},
-    {  "*AxB",  "",       false,      "A",         "*A",          "A"},
-    // Sync enabled, token error on both accounts.
-    {  "*xAxB", "AB",     false,      "X",         "*xA",         ""},
-    {  "*xAxB", "BA",     false,      "X",         "*xA",         ""},
-    {  "*xAxB", "A",      false,      "X",         "*xA",         ""},
-    {  "*xAxB", "B",      false,      "X",         "*xA",         ""},
-    {  "*xAxB", "",       false,      "",          "*xA",         ""},
-    // Sync disabled.
-    {  "AB",    "AB",     false,      "",          "AB",          "AB"},
-    {  "AB",    "BA",     false,      "",          "AB",          "BA"},
-    {  "AB",    "A",      false,      "B",         "AB",          "AB"},
-    {  "AB",    "B",      false,      "A",         "AB",          "BA"},
-    {  "AB",    "",       false,      "AB",        "AB",          "AB"},
-    // Sync disabled, token error on first account.
-    {  "xAB",   "AB",     false,      "X",         "",            ""},
-    {  "xAB",   "BA",     false,      "XB",        "B",           "B"},
-    {  "xAB",   "A",      false,      "X",         "",            ""},
-    {  "xAB",   "B",      false,      "",          "B",           "B"},
-    {  "xAB",   "",       false,      "B",         "B",           "B"},
-    // Sync disabled, token error on second account.
-    {  "AxB",   "AB",     false,      "XA",        "A",           "A"},
-    {  "AxB",   "BA",     false,      "X",         "",            ""},
-    {  "AxB",   "A",      false,      "",          "A",           "A"},
-    {  "AxB",   "B",      false,      "X",         "",            ""},
-    {  "AxB",   "",       false,      "A",         "A",           "A"},
-    // Sync disabled, token error on both accounts.
-    {  "xAxB",  "AB",     false,      "X",         "",            ""},
-    {  "xAxB",  "BA",     false,      "X",         "",            ""},
-    {  "xAxB",  "A",      false,      "X",         "",            ""},
-    {  "xAxB",  "B",      false,      "X",         "",            ""},
-    {  "xAxB",  "",       false,      "",          "",            ""},
-
-    // Account marked as invalid in cookies.
-    // Do not logout. Regression tests for http://crbug.com/854799
-    {  "",      "xA",     false,      "",          "",            "xA"},
-    {  "",      "xAxB",   false,      "",          "",            "xAxB"},
-    {  "xA",    "xA",     false,      "",          "",            "xA"},
-    {  "xAB",   "xAB",    false,      "",          "B",           "xAB"},
-    {  "AxB",   "AxC",    false,      "",          "A",           "AxC"},
-    {  "B",     "xAB",    false,      "",          "B",           "xAB"},
-    {  "*xA",   "xA",     false,      "",          "*xA",         "xA"},
-    {  "*xA",   "xB",     false,      "",          "*xA",         "xB"},
-    {  "*xAB",  "xAB",    false,      "",          "*xAB",        "xAB"},
-    // Appending a new cookie after the invalid one.
-    {  "B",     "xA",     false,      "B",         "B",           "xAB"},
-    {  "xAB",   "xA",     false,      "B",         "B",           "xAB"},
-    // Cookies can be refreshed in pace, without logout.
-    {  "AB",    "xAB",    false,      "A",         "AB",          "AB"},
-    {  "*AB",   "xBxA",   false,      "BA",        "*AB",         "BA"},
-    // Logout when necessary.
-    {  "",      "xAB",    false,      "X",         "",            ""},
-    {  "xAB",   "xAC",    false,      "X",         "",            ""},
-    {  "xAB",   "AxC",    false,      "X",         "",            ""},
-    {  "*xAB",  "xABC",   false,      "X",         "*xA",         ""},
-    {  "xAB",   "xABC",   false,      "X",         "",            ""},
-
-    // Miscellaneous cases.
-    // Check that unknown Gaia accounts are signed out.
-    {  "",      "A",      true,       "X",         "",            ""},
-    {  "",      "A",      false,      "X",         "",            ""},
-    {  "*A",    "AB",     true,       "XA",        "*A",          "A"},
-    {  "*A",    "AB",     false,      "XA",        "*A",          "A"},
-    // Check that Gaia default account is kept in first position.
-    {  "AB",    "BC",     true,       "XBA",       "AB",          "BA"},
-    {  "AB",    "BC",     false,      "XBA",       "AB",          "BA"},
-    // Required for idempotency check.
-    {  "",      "",       false,      "",          "",            ""},
-    {  "*A",    "A",      false,      "",          "*A",          "A"},
-    {  "A",     "A",      false,      "",          "A",           "A"},
-    {  "B",     "B",      false,      "",          "B",           "B"},
-    {  "*xA",   "",       false,      "",          "*xA",         ""},
-    {  "*xAB",  "B",      false,      "",          "*xAB",        "B"},
-    {  "A",     "AxC",    false,      "",          "A",           "AxC"},
-};
-// clang-format on
+// Pretty prints a AccountReconcilorTestTableParam. Used by gtest.
+void PrintTo(const AccountReconcilorTestTableParam& param, ::std::ostream* os) {
+  *os << "Tokens: " << param.tokens << ". Cookies: " << param.cookies
+      << ". First reconcile: "
+      << (param.is_first_reconcile == IsFirstReconcile::kFirst ? "true"
+                                                               : "false");
+}
 
 // Parameterized version of AccountReconcilorTest.
-class AccountReconcilorTestDice
+class AccountReconcilorTestTable
     : public AccountReconcilorTest,
-      public ::testing::WithParamInterface<AccountReconcilorTestDiceParam> {
+      public ::testing::WithParamInterface<AccountReconcilorTestTableParam> {
  protected:
   struct Account {
     std::string email;
@@ -664,7 +503,7 @@
     }
   };
 
-  AccountReconcilorTestDice() {
+  AccountReconcilorTestTable() {
     accounts_['A'] = {"a@gmail.com", "A"};
     accounts_['B'] = {"b@gmail.com", "B"};
     accounts_['C'] = {"c@gmail.com", "C"};
@@ -730,11 +569,13 @@
   }
 
   // Checks that reconcile is idempotent.
-  void CheckReconcileIdempotent(const AccountReconcilorTestDiceParam& param) {
+  void CheckReconcileIdempotent(
+      const std::vector<AccountReconcilorTestTableParam>& params,
+      const AccountReconcilorTestTableParam& param) {
     // Simulate another reconcile based on the results of this one: find the
     // corresponding row in the table and check that it does nothing.
-    for (const AccountReconcilorTestDiceParam& row : kDiceParams) {
-      if (row.is_first_reconcile)
+    for (const AccountReconcilorTestTableParam& row : params) {
+      if (row.is_first_reconcile == IsFirstReconcile::kFirst)
         continue;
       if (strcmp(row.tokens, param.tokens_after_reconcile) != 0)
         continue;
@@ -763,14 +604,230 @@
   std::map<char, Account> accounts_;
 };
 
+#if !defined(OS_CHROMEOS)
+
+// This method requires the use of the |TestSigninClient| to be created from the
+// |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded|
+// method with an empty implementation. On MacOS, the normal implementation
+// causes the try_bots to time out.
+TEST_P(AccountReconcilorMirrorEndpointParamTest, SigninManagerRegistration) {
+  AccountReconcilor* reconcilor = GetMockReconcilor();
+  ASSERT_TRUE(reconcilor);
+  ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService());
+
+  account_tracker()->SeedAccountInfo("12345", "user@gmail.com");
+  signin_manager()->SignIn("12345", "user@gmail.com", "password");
+  ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+
+  EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
+
+  signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
+                            signin_metrics::SignoutDelete::IGNORE_METRIC);
+  ASSERT_FALSE(reconcilor->IsRegisteredWithTokenService());
+}
+
+// This method requires the use of the |TestSigninClient| to be created from the
+// |ChromeSigninClientFactory| because it overrides the |GoogleSigninSucceeded|
+// method with an empty implementation. On MacOS, the normal implementation
+// causes the try_bots to time out.
+TEST_P(AccountReconcilorMirrorEndpointParamTest, Reauth) {
+  const std::string email = "user@gmail.com";
+  const std::string account_id = ConnectProfileToAccount("12345", email);
+
+  AccountReconcilor* reconcilor = GetMockReconcilor();
+  ASSERT_TRUE(reconcilor);
+  ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+
+  // Simulate reauth.  The state of the reconcilor should not change.
+  signin_manager()->OnExternalSigninCompleted(email);
+  ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+}
+
+#endif  // !defined(OS_CHROMEOS)
+
+TEST_P(AccountReconcilorMirrorEndpointParamTest, ProfileAlreadyConnected) {
+  ConnectProfileToAccount("12345", "user@gmail.com");
+
+  AccountReconcilor* reconcilor = GetMockReconcilor();
+  ASSERT_TRUE(reconcilor);
+  ASSERT_TRUE(reconcilor->IsRegisteredWithTokenService());
+}
+
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+
+// clang-format off
+const std::vector<AccountReconcilorTestTableParam> kDiceParams = {
+    // This table encodes the initial state and expectations of a reconcile.
+    // The syntax is:
+    // - Tokens:
+    //   A, B, C: Accounts for which we have a token in Chrome.
+    //   *: The next account is the main Chrome account (i.e. in SigninManager).
+    //   x: The next account has a token error.
+    // - Cookies:
+    //   A, B, C: Accounts in the Gaia cookie (returned by ListAccounts).
+    //   x: The next cookie is marked "invalid".
+    // - First Run: true if this is the first reconcile (i.e. Chrome startup).
+    // - API calls:
+    //   X: Logout all accounts.
+    //   A, B, C: Merge account.
+    // -------------------------------------------------------------------------
+    // Tokens | Cookies |           First Run         | Gaia calls | Tokens after | Cookies after
+    // -------------------------------------------------------------------------
+
+    // First reconcile (Chrome restart): Rebuild the Gaia cookie to match the
+    // tokens. Make the Sync account the default account in the Gaia cookie.
+    // Sync enabled.
+    {  "*AB",   "AB",     IsFirstReconcile::kFirst,      "",          "*AB",         "AB"},
+    {  "*AB",   "BA",     IsFirstReconcile::kFirst,     "XAB",       "*AB",         "AB"},
+    {  "*AB",   "A",      IsFirstReconcile::kFirst,       "B",         "*AB",         "AB"},
+    {  "*AB",   "B",      IsFirstReconcile::kFirst,      "XAB",       "*AB",         "AB"},
+    {  "*AB",   "",       IsFirstReconcile::kFirst,      "AB",        "*AB",         "AB"},
+    // Sync enabled, token error on primary.
+    {  "*xAB",  "AB",     IsFirstReconcile::kFirst,       "X",         "*xA",         ""},
+    {  "*xAB",  "BA",     IsFirstReconcile::kFirst,       "XB",        "*xAB",        "B"},
+    {  "*xAB",  "A",      IsFirstReconcile::kFirst,       "X",         "*xA",         ""},
+    {  "*xAB",  "B",      IsFirstReconcile::kFirst,       "",          "*xAB",        "B"},
+    {  "*xAB",  "",       IsFirstReconcile::kFirst,       "B",         "*xAB",        "B"},
+    // Sync enabled, token error on secondary.
+    {  "*AxB",  "AB",     IsFirstReconcile::kFirst,     "XA",        "*A",          "A"},
+    {  "*AxB",  "BA",     IsFirstReconcile::kFirst,     "XA",        "*A",          "A"},
+    {  "*AxB",  "A",      IsFirstReconcile::kFirst,     "",          "*A",          "A"},
+    {  "*AxB",  "B",      IsFirstReconcile::kFirst,     "XA",        "*A",          "A"},
+    {  "*AxB",  "",       IsFirstReconcile::kFirst,     "A",         "*A",          "A"},
+    // Sync enabled, token error on both accounts.
+    {  "*xAxB", "AB",     IsFirstReconcile::kFirst,      "X",         "*xA",         ""},
+    {  "*xAxB", "BA",     IsFirstReconcile::kFirst,      "X",         "*xA",         ""},
+    {  "*xAxB", "A",      IsFirstReconcile::kFirst,      "X",         "*xA",         ""},
+    {  "*xAxB", "B",      IsFirstReconcile::kFirst,      "X",         "*xA",         ""},
+    {  "*xAxB", "",       IsFirstReconcile::kFirst,      "",          "*xA",         ""},
+    // Sync disabled.
+    {  "AB",    "AB",     IsFirstReconcile::kFirst,      "",          "AB",          "AB"},
+    {  "AB",    "BA",     IsFirstReconcile::kFirst,      "",          "AB",          "BA"},
+    {  "AB",    "A",      IsFirstReconcile::kFirst,      "B",         "AB",          "AB"},
+    {  "AB",    "B",      IsFirstReconcile::kFirst,      "A",         "AB",          "BA"},
+    {  "AB",    "",       IsFirstReconcile::kFirst,      "AB",        "AB",          "AB"},
+    // Sync disabled, token error on first account.
+    {  "xAB",   "AB",     IsFirstReconcile::kFirst,      "XB",        "B",           "B"},
+    {  "xAB",   "BA",     IsFirstReconcile::kFirst,      "XB",        "B",           "B"},
+    {  "xAB",   "A",      IsFirstReconcile::kFirst,      "XB",        "B",           "B"},
+    {  "xAB",   "B",      IsFirstReconcile::kFirst,      "",          "B",           "B"},
+    {  "xAB",   "",       IsFirstReconcile::kFirst,      "B",         "B",           "B"},
+    // Sync disabled, token error on second account       .
+    {  "AxB",   "AB",     IsFirstReconcile::kFirst,      "XA",        "A",           "A"},
+    {  "AxB",   "BA",     IsFirstReconcile::kFirst,      "XA",        "A",           "A"},
+    {  "AxB",   "A",      IsFirstReconcile::kFirst,      "",          "A",           "A"},
+    {  "AxB",   "B",      IsFirstReconcile::kFirst,      "XA",        "A",           "A"},
+    {  "AxB",   "",       IsFirstReconcile::kFirst,      "A",         "A",           "A"},
+    // Sync disabled, token error on both accounts.
+    {  "xAxB",  "AB",     IsFirstReconcile::kFirst,     "X",         "",            ""},
+    {  "xAxB",  "BA",     IsFirstReconcile::kFirst,     "X",         "",            ""},
+    {  "xAxB",  "A",      IsFirstReconcile::kFirst,     "X",         "",            ""},
+    {  "xAxB",  "B",      IsFirstReconcile::kFirst,     "X",         "",            ""},
+    {  "xAxB",  "",       IsFirstReconcile::kFirst,     "",          "",            ""},
+
+    // Chrome is running: Do not change the order of accounts already present in
+    // the Gaia cookies.
+    // Sync enabled.
+    {  "*AB",   "AB",     IsFirstReconcile::kNotFirst,   "",          "*AB",         "AB"},
+    {  "*AB",   "BA",     IsFirstReconcile::kNotFirst,   "",          "*AB",         "BA"},
+    {  "*AB",   "A",      IsFirstReconcile::kNotFirst,   "B",         "*AB",         "AB"},
+    {  "*AB",   "B",      IsFirstReconcile::kNotFirst,   "A",         "*AB",         "BA"},
+    {  "*AB",   "",       IsFirstReconcile::kNotFirst,   "AB",        "*AB",         "AB"},
+    // Sync enabled, token error on primary.
+    {  "*xAB",  "AB",     IsFirstReconcile::kNotFirst,   "X",         "*xA",         ""},
+    {  "*xAB",  "BA",     IsFirstReconcile::kNotFirst,   "XB",        "*xAB",        "B"},
+    {  "*xAB",  "A",      IsFirstReconcile::kNotFirst,   "X",         "*xA",         ""},
+    {  "*xAB",  "B",      IsFirstReconcile::kNotFirst,   "",          "*xAB",        "B"},
+    {  "*xAB",  "",       IsFirstReconcile::kNotFirst,   "B",         "*xAB",        "B"},
+    // Sync enabled, token error on secondary.
+    {  "*AxB",  "AB",     IsFirstReconcile::kNotFirst,   "XA",        "*A",          "A"},
+    {  "*AxB",  "BA",     IsFirstReconcile::kNotFirst,   "XA",        "*A",          "A"},
+    {  "*AxB",  "A",      IsFirstReconcile::kNotFirst,   "",          "*A",          "A"},
+    {  "*AxB",  "B",      IsFirstReconcile::kNotFirst,   "XA",        "*A",          "A"},
+    {  "*AxB",  "",       IsFirstReconcile::kNotFirst,   "A",         "*A",          "A"},
+    // Sync enabled, token error on both accounts.
+    {  "*xAxB", "AB",     IsFirstReconcile::kNotFirst,   "X",         "*xA",         ""},
+    {  "*xAxB", "BA",     IsFirstReconcile::kNotFirst,   "X",         "*xA",         ""},
+    {  "*xAxB", "A",      IsFirstReconcile::kNotFirst,   "X",         "*xA",         ""},
+    {  "*xAxB", "B",      IsFirstReconcile::kNotFirst,   "X",         "*xA",         ""},
+    {  "*xAxB", "",       IsFirstReconcile::kNotFirst,   "",          "*xA",         ""},
+    // Sync disabled.
+    {  "AB",    "AB",     IsFirstReconcile::kNotFirst,   "",          "AB",          "AB"},
+    {  "AB",    "BA",     IsFirstReconcile::kNotFirst,   "",          "AB",          "BA"},
+    {  "AB",    "A",      IsFirstReconcile::kNotFirst,   "B",         "AB",          "AB"},
+    {  "AB",    "B",      IsFirstReconcile::kNotFirst,   "A",         "AB",          "BA"},
+    {  "AB",    "",       IsFirstReconcile::kNotFirst,   "AB",        "AB",          "AB"},
+    // Sync disabled, token error on first account.
+    {  "xAB",   "AB",     IsFirstReconcile::kNotFirst,   "X",         "",            ""},
+    {  "xAB",   "BA",     IsFirstReconcile::kNotFirst,   "XB",        "B",           "B"},
+    {  "xAB",   "A",      IsFirstReconcile::kNotFirst,   "X",         "",            ""},
+    {  "xAB",   "B",      IsFirstReconcile::kNotFirst,   "",          "B",           "B"},
+    {  "xAB",   "",       IsFirstReconcile::kNotFirst,   "B",         "B",           "B"},
+    // Sync disabled, token error on second account.
+    {  "AxB",   "AB",     IsFirstReconcile::kNotFirst,   "XA",        "A",           "A"},
+    {  "AxB",   "BA",     IsFirstReconcile::kNotFirst,   "X",         "",            ""},
+    {  "AxB",   "A",      IsFirstReconcile::kNotFirst,   "",          "A",           "A"},
+    {  "AxB",   "B",      IsFirstReconcile::kNotFirst,   "X",         "",            ""},
+    {  "AxB",   "",       IsFirstReconcile::kNotFirst,   "A",         "A",           "A"},
+    // Sync disabled, token error on both accounts.
+    {  "xAxB",  "AB",     IsFirstReconcile::kNotFirst,   "X",         "",            ""},
+    {  "xAxB",  "BA",     IsFirstReconcile::kNotFirst,   "X",         "",            ""},
+    {  "xAxB",  "A",      IsFirstReconcile::kNotFirst,   "X",         "",            ""},
+    {  "xAxB",  "B",      IsFirstReconcile::kNotFirst,   "X",         "",            ""},
+    {  "xAxB",  "",       IsFirstReconcile::kNotFirst,   "",          "",            ""},
+
+    // Account marked as invalid in cookies.
+    // Do not logout. Regression tests for http://crbug.com/854799
+    {  "",      "xA",     IsFirstReconcile::kNotFirst,  "",          "",            "xA"},
+    {  "",      "xAxB",   IsFirstReconcile::kNotFirst,  "",          "",            "xAxB"},
+    {  "xA",    "xA",     IsFirstReconcile::kNotFirst,  "",          "",            "xA"},
+    {  "xAB",   "xAB",    IsFirstReconcile::kNotFirst,  "",          "B",           "xAB"},
+    {  "AxB",   "AxC",    IsFirstReconcile::kNotFirst,  "",          "A",           "AxC"},
+    {  "B",     "xAB",    IsFirstReconcile::kNotFirst,  "",          "B",           "xAB"},
+    {  "*xA",   "xA",     IsFirstReconcile::kNotFirst,  "",          "*xA",         "xA"},
+    {  "*xA",   "xB",     IsFirstReconcile::kNotFirst,  "",          "*xA",         "xB"},
+    {  "*xAB",  "xAB",    IsFirstReconcile::kNotFirst,  "",          "*xAB",        "xAB"},
+    // Appending a new cookie after the invalid one.
+    {  "B",     "xA",     IsFirstReconcile::kNotFirst, "B",         "B",           "xAB"},
+    {  "xAB",   "xA",     IsFirstReconcile::kNotFirst, "B",         "B",           "xAB"},
+    // Cookies can be refreshed in pace, without logout.
+    {  "AB",    "xAB",    IsFirstReconcile::kNotFirst,  "A",         "AB",          "AB"},
+    {  "*AB",   "xBxA",   IsFirstReconcile::kNotFirst,  "BA",        "*AB",         "BA"},
+    // Logout when necessary.
+    {  "",      "xAB",    IsFirstReconcile::kNotFirst,  "X",         "",            ""},
+    {  "xAB",   "xAC",    IsFirstReconcile::kNotFirst,  "X",         "",            ""},
+    {  "xAB",   "AxC",    IsFirstReconcile::kNotFirst,  "X",         "",            ""},
+    {  "*xAB",  "xABC",   IsFirstReconcile::kNotFirst,  "X",         "*xA",         ""},
+    {  "xAB",   "xABC",   IsFirstReconcile::kNotFirst,  "X",         "",            ""},
+
+    // Miscellaneous cases.
+    // Check that unknown Gaia accounts are signed out.
+    {  "",      "A",      IsFirstReconcile::kFirst,     "X",         "",            ""},
+    {  "",      "A",      IsFirstReconcile::kNotFirst,  "X",         "",            ""},
+    {  "*A",    "AB",     IsFirstReconcile::kFirst,     "XA",        "*A",          "A"},
+    {  "*A",    "AB",     IsFirstReconcile::kNotFirst,  "XA",        "*A",          "A"},
+    // Check that Gaia default account is kept in first position.
+    {  "AB",    "BC",     IsFirstReconcile::kFirst,     "XBA",       "AB",          "BA"},
+    {  "AB",    "BC",     IsFirstReconcile::kNotFirst,  "XBA",       "AB",          "BA"},
+    // Required for idempotency check.
+    {  "",      "",       IsFirstReconcile::kNotFirst,  "",          "",            ""},
+    {  "*A",    "A",      IsFirstReconcile::kNotFirst,  "",          "*A",          "A"},
+    {  "A",     "A",      IsFirstReconcile::kNotFirst,  "",          "A",           "A"},
+    {  "B",     "B",      IsFirstReconcile::kNotFirst,  "",          "B",           "B"},
+    {  "*xA",   "",       IsFirstReconcile::kNotFirst,  "",          "*xA",         ""},
+    {  "*xAB",  "B",      IsFirstReconcile::kNotFirst,  "",          "*xAB",        "B"},
+    {  "A",     "AxC",    IsFirstReconcile::kNotFirst,  "",          "A",           "AxC"},
+};
+// clang-format on
+
 // Checks one row of the kDiceParams table above.
-TEST_P(AccountReconcilorTestDice, TableRowTest) {
+TEST_P(AccountReconcilorTestTable, TableRowTest) {
   // Enable Dice.
   SetAccountConsistency(signin::AccountConsistencyMethod::kDice);
 
   // Check that reconcile is idempotent: when called twice in a row it should do
   // nothing on the second call.
-  CheckReconcileIdempotent(GetParam());
+  CheckReconcileIdempotent(kDiceParams, GetParam());
 
   // Setup tokens.
   std::vector<Token> tokens_before_reconcile =
@@ -832,7 +889,8 @@
   // Reconcile.
   AccountReconcilor* reconcilor = GetMockReconcilor();
   ASSERT_TRUE(reconcilor->first_execution_);
-  reconcilor->first_execution_ = GetParam().is_first_reconcile;
+  reconcilor->first_execution_ =
+      GetParam().is_first_reconcile == IsFirstReconcile::kFirst ? true : false;
   reconcilor->StartReconcile();
   for (int i = 0; GetParam().gaia_api_calls[i] != '\0'; ++i) {
     if (GetParam().gaia_api_calls[i] == 'X')
@@ -859,9 +917,10 @@
   base::RunLoop().RunUntilIdle();
 }
 
-INSTANTIATE_TEST_CASE_P(DiceTable,
-                        AccountReconcilorTestDice,
-                        ::testing::ValuesIn(kDiceParams));
+INSTANTIATE_TEST_CASE_P(
+    DiceTable,
+    AccountReconcilorTestTable,
+    ::testing::ValuesIn(GenerateTestCasesFromParams(kDiceParams)));
 
 // Tests that the AccountReconcilor is always registered.
 TEST_F(AccountReconcilorTest, DiceTokenServiceRegistration) {
@@ -1241,10 +1300,154 @@
 
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
+// clang-format off
+const std::vector<AccountReconcilorTestTableParam> kMirrorParams = {
+    // This table encodes the initial state and expectations of a reconcile.
+    // The syntax is:
+    // - Tokens:
+    //   A, B, C: Accounts for which we have a token in Chrome.
+    //   *: The next account is the main Chrome account (i.e. in SigninManager).
+    //   x: The next account has a token error.
+    // - Cookies:
+    //   A, B, C: Accounts in the Gaia cookie (returned by ListAccounts).
+    //   x: The next cookie is marked "invalid".
+    // - First Run: true if this is the first reconcile (i.e. Chrome startup).
+    //   M: Multilogin.
+    // -----------------
+    // -------------------------------------------------------------------------
+    // Tokens | Cookies |          First Run        | Gaia calls | Tokens after | Cookies after
+    // -------------------------------------------------------------------------
+
+    // First reconcile (Chrome restart): Rebuild the Gaia cookie to match the
+    // tokens. Make the Sync account the default account in the Gaia cookie.
+    // Sync enabled.
+    {  "*AB",   "AB",     IsFirstReconcile::kBoth,       "",          "*AB",         "AB"},
+    {  "*AB",   "BA",     IsFirstReconcile::kBoth,       "M",         "*AB",         "AB"},
+    {  "*AB",   "A",      IsFirstReconcile::kBoth,       "M",         "*AB",         "AB"},
+    {  "*AB",   "B",      IsFirstReconcile::kBoth,       "M",         "*AB",         "AB"},
+    {  "*AB",   "",       IsFirstReconcile::kBoth,       "M",         "*AB",         "AB"},
+    // Sync enabled, token error on primary.
+    // Sync enabled, token error on secondary.
+    {  "*AxB",  "AB",     IsFirstReconcile::kBoth,       "M",         "*AxB",         "A"},
+    {  "*AxB",  "BA",     IsFirstReconcile::kBoth,       "M",         "*AxB",         "A"},
+    {  "*AxB",  "A",      IsFirstReconcile::kBoth,       "",          "*AxB",         "" },
+    {  "*AxB",  "B",      IsFirstReconcile::kBoth,       "M",         "*AxB",         "A"},
+    {  "*AxB",  "",       IsFirstReconcile::kBoth,       "M",         "*AxB",          "A"},
+
+    // Cookies can be refreshed in pace, without logout.
+    {  "*AB",   "xBxA",   IsFirstReconcile::kBoth,       "M",         "*AB",         "AB"},
+
+    // Check that unknown Gaia accounts are signed out.
+    {  "*A",    "AB",     IsFirstReconcile::kBoth,       "M",          "*A",          "A"},
+    // Check that the previous case is idempotent..
+    {  "*A",    "A",      IsFirstReconcile::kBoth,       "",           "*A",          ""},
+};
+// clang-format on
+
+// Parameterized version of AccountReconcilorTest that tests Mirror
+// implementation with Multilogin endpoint.
+class AccountReconcilorTestMirrorMultilogin
+    : public AccountReconcilorTestTable {
+ public:
+  AccountReconcilorTestMirrorMultilogin() = default;
+
+ protected:
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AccountReconcilorTestMirrorMultilogin);
+};
+
+// Checks one row of the kDiceParams table above.
+TEST_P(AccountReconcilorTestMirrorMultilogin, TableRowTest) {
+  // Enable Mirror.
+  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+  scoped_feature_list_.InitAndEnableFeature(kUseMultiloginEndpoint);
+
+  // Setup tokens.
+  std::vector<Token> tokens_before_reconcile =
+      ParseTokenString(GetParam().tokens);
+  for (const Token& token : tokens_before_reconcile) {
+    std::string account_id =
+        PickAccountIdForAccount(token.gaia_id, token.email);
+    if (token.is_authenticated)
+      ConnectProfileToAccount(token.gaia_id, token.email);
+    else
+      token_service()->UpdateCredentials(account_id, "refresh_token");
+    if (token.has_error) {
+      token_service()->UpdateAuthErrorForTesting(
+          account_id, GoogleServiceAuthError(
+                          GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+    }
+  }
+  VerifyCurrentTokens(tokens_before_reconcile);
+
+  // Setup cookies.
+  std::vector<Cookie> cookies = ParseCookieString(GetParam().cookies);
+  ConfigureCookieManagerService(cookies);
+
+  // Call list accounts now so that the next call completes synchronously.
+  cookie_manager_service()->ListAccounts(nullptr, nullptr, "foo");
+  base::RunLoop().RunUntilIdle();
+
+  // Setup expectations.
+  testing::InSequence mock_sequence;
+  bool logout_action = false;
+  for (int i = 0; GetParam().gaia_api_calls[i] != '\0'; ++i) {
+    if (GetParam().gaia_api_calls[i] == 'M') {
+      std::vector<std::string> accounts_to_send;
+      for (int i = 0; GetParam().cookies_after_reconcile[i] != '\0'; ++i) {
+        std::string account_to_send =
+            std::string(1, GetParam().cookies_after_reconcile[i]);
+        accounts_to_send.push_back(PickAccountIdForAccount(
+            account_to_send,
+            accounts_[GetParam().cookies_after_reconcile[i]].email));
+      }
+      EXPECT_CALL(*GetMockReconcilor(),
+                  PerformSetCookiesAction(accounts_to_send))
+          .Times(1);
+    }
+  }
+  if (!logout_action) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction())
+        .Times(0);
+  }
+
+  // Reconcile.
+  AccountReconcilor* reconcilor = GetMockReconcilor();
+  ASSERT_TRUE(reconcilor);
+  ASSERT_TRUE(reconcilor->first_execution_);
+  reconcilor->first_execution_ =
+      GetParam().is_first_reconcile == IsFirstReconcile::kFirst ? true : false;
+  reconcilor->StartReconcile();
+
+  SimulateSetAccountsInCookieCompleted(reconcilor,
+                                       GoogleServiceAuthError::AuthErrorNone());
+
+  ASSERT_FALSE(reconcilor->is_reconcile_started_);
+  ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState());
+  VerifyCurrentTokens(ParseTokenString(GetParam().tokens_after_reconcile));
+
+  testing::Mock::VerifyAndClearExpectations(GetMockReconcilor());
+
+  // // Another reconcile is sometimes triggered if Chrome accounts have
+  // changed. Allow it to finish.
+  EXPECT_CALL(*GetMockReconcilor(), PerformSetCookiesAction(testing::_))
+      .WillRepeatedly(testing::Return());
+  EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction())
+      .WillRepeatedly(testing::Return());
+  ConfigureCookieManagerService({});
+  base::RunLoop().RunUntilIdle();
+}
+
+INSTANTIATE_TEST_CASE_P(
+    DiceTableMirrorMultilogin,
+    AccountReconcilorTestMirrorMultilogin,
+    ::testing::ValuesIn(GenerateTestCasesFromParams(kMirrorParams)));
+
 // Tests that reconcile cannot start before the tokens are loaded, and is
 // automatically started when tokens are loaded.
-TEST_F(AccountReconcilorTest, TokensNotLoaded) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, TokensNotLoaded) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseNoAccounts();
@@ -1261,23 +1464,39 @@
   token_service()->LoadCredentials(account_id);
 #endif
 
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+  } else {
+    std::vector<std::string> accounts_to_set = {account_id};
+    EXPECT_CALL(*GetMockReconcilor(), PerformSetCookiesAction(accounts_to_set));
+  }
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
   base::RunLoop().RunUntilIdle();
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id,
-                                      GoogleServiceAuthError::AuthErrorNone());
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id, GoogleServiceAuthError::AuthErrorNone());
+  } else {
+    SimulateSetAccountsInCookieCompleted(
+        reconcilor, GoogleServiceAuthError::AuthErrorNone());
+  }
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
   ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_OK, reconcilor->GetState());
 }
 
-TEST_F(AccountReconcilorTest, GetAccountsFromCookieSuccess) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, GetAccountsFromCookieSuccess) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
       {"user@gmail.com", "12345", false /* valid */, false /* signed_out */,
        true /* verified */});
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+  } else {
+    std::vector<std::string> accounts_to_send = {account_id};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
 
   AccountReconcilor* reconcilor = GetMockReconcilor();
   ASSERT_TRUE(reconcilor);
@@ -1297,8 +1516,8 @@
   ASSERT_EQ(0u, signed_out_accounts.size());
 }
 
-TEST_F(AccountReconcilorTest, GetAccountsFromCookieFailure) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, GetAccountsFromCookieFailure) {
+  ;
   ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseWebLoginRequired();
 
@@ -1321,8 +1540,7 @@
   ASSERT_EQ(signin_metrics::ACCOUNT_RECONCILOR_ERROR, reconcilor->GetState());
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileNoop) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoop) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
 
@@ -1338,15 +1556,17 @@
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
-  histogram_tester()->ExpectTotalCount(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
-      signin_metrics::ACCOUNTS_SAME, 1);
+  if (!GetParam()) {
+    histogram_tester()->ExpectTotalCount(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
+        signin_metrics::ACCOUNTS_SAME, 1);
+  }
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileCookiesDisabled) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+       StartReconcileCookiesDisabled) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
@@ -1366,8 +1586,8 @@
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileContentSettings) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+       StartReconcileContentSettings) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
@@ -1386,8 +1606,8 @@
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileContentSettingsGaiaUrl) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+       StartReconcileContentSettingsGaiaUrl) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
@@ -1401,8 +1621,8 @@
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileContentSettingsNonGaiaUrl) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+       StartReconcileContentSettingsNonGaiaUrl) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
@@ -1416,8 +1636,8 @@
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileContentSettingsInvalidPattern) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+       StartReconcileContentSettingsInvalidPattern) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
@@ -1441,8 +1661,7 @@
 // tests makes sure that an email like "Dot.S@hmail.com", as seen by the
 // token service, will be considered the same as "dots@gmail.com" as returned
 // by gaia::ParseListAccountsData().
-TEST_F(AccountReconcilorTest, StartReconcileNoopWithDots) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoopWithDots) {
   if (account_tracker()->GetMigrationState() !=
       AccountTrackerService::MIGRATION_NOT_STARTED) {
     return;
@@ -1459,19 +1678,20 @@
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
-      signin_metrics::ACCOUNTS_SAME, 1);
+  if (!GetParam()) {
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
+        signin_metrics::ACCOUNTS_SAME, 1);
+  }
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileNoopMultiple) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileNoopMultiple) {
   const std::string account_id =
-      ConnectProfileToAccount("12345", "user@gmail.com");
+      ConnectProfileToAccount("67890", "user@gmail.com");
   const std::string account_id2 =
-      PickAccountIdForAccount("67890", "other@gmail.com");
+      PickAccountIdForAccount("12345", "other@gmail.com");
   cookie_manager_service()->SetListAccountsResponseTwoAccounts(
-      "user@gmail.com", "12345", "other@gmail.com", "67890");
+      "user@gmail.com", "67890", "other@gmail.com", "12345");
   token_service()->UpdateCredentials(account_id2, "refresh_token");
 
   AccountReconcilor* reconcilor = GetMockReconcilor();
@@ -1481,43 +1701,57 @@
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
-  histogram_tester()->ExpectTotalCount(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
-      signin_metrics::ACCOUNTS_SAME, 1);
+  if (!GetParam()) {
+    histogram_tester()->ExpectTotalCount(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun", 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
+        signin_metrics::ACCOUNTS_SAME, 1);
+  }
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileAddToCookie) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileAddToCookie) {
   const std::string account_id =
-      ConnectProfileToAccount("12345", "user@gmail.com");
+      ConnectProfileToAccount("67890", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
   cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
-                                                              "12345");
+                                                              "67890");
 
   const std::string account_id2 =
-      PickAccountIdForAccount("67890", "other@gmail.com");
+      PickAccountIdForAccount("12345", "other@gmail.com");
   token_service()->UpdateCredentials(account_id2, "refresh_token");
 
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
+  } else {
+    std::vector<std::string> accounts_to_send = {account_id, account_id2};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
 
   AccountReconcilor* reconcilor = GetMockReconcilor();
   reconcilor->StartReconcile();
 
   base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id2,
-                                      GoogleServiceAuthError::AuthErrorNone());
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id2, GoogleServiceAuthError::AuthErrorNone());
+  } else {
+    SimulateSetAccountsInCookieCompleted(
+        reconcilor, GoogleServiceAuthError::AuthErrorNone());
+  }
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
-      signin_metrics::ACCOUNTS_SAME, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
+  if (!GetParam()) {
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
+        signin_metrics::ACCOUNTS_SAME, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
+  }
 
   base::HistogramTester::CountsMap expected_counts;
   expected_counts["Signin.Reconciler.Duration.Success"] = 1;
@@ -1584,8 +1818,8 @@
 // This test does not run on ChromeOS because it calls
 // FakeSigninManagerForTesting::SignOut() which doesn't exist for ChromeOS.
 
-TEST_F(AccountReconcilorTest, SignoutAfterErrorDoesNotRecordUma) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+       SignoutAfterErrorDoesNotRecordUma) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
@@ -1596,7 +1830,13 @@
       PickAccountIdForAccount("67890", "other@gmail.com");
   token_service()->UpdateCredentials(account_id2, "refresh_token");
 
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
+  } else {
+    std::vector<std::string> accounts_to_send = {account_id, account_id2};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
 
   AccountReconcilor* reconcilor = GetMockReconcilor();
   reconcilor->StartReconcile();
@@ -1605,7 +1845,11 @@
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
   GoogleServiceAuthError error(
       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id2, error);
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(reconcilor, account_id2, error);
+  } else {
+    SimulateSetAccountsInCookieCompleted(reconcilor, error);
+  }
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
   EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
@@ -1614,107 +1858,166 @@
 
   base::HistogramTester::CountsMap expected_counts;
   expected_counts["Signin.Reconciler.Duration.Failure"] = 1;
-  EXPECT_THAT(histogram_tester()->GetTotalCountsForPrefix(
-                  "Signin.Reconciler.Duration.Failure"),
-              testing::ContainerEq(expected_counts));
+  if (!GetParam()) {
+    EXPECT_THAT(histogram_tester()->GetTotalCountsForPrefix(
+                    "Signin.Reconciler.Duration.Failure"),
+                testing::ContainerEq(expected_counts));
+  }
 }
 
 #endif  // !defined(OS_CHROMEOS)
 
-TEST_F(AccountReconcilorTest, StartReconcileRemoveFromCookie) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+       StartReconcileRemoveFromCookie) {
   const std::string account_id =
-      ConnectProfileToAccount("12345", "user@gmail.com");
+      ConnectProfileToAccount("67890", "user@gmail.com");
   token_service()->UpdateCredentials(account_id, "refresh_token");
   cookie_manager_service()->SetListAccountsResponseTwoAccounts(
-      "user@gmail.com", "12345", "other@gmail.com", "67890");
+      "user@gmail.com", "67890", "other@gmail.com", "12345");
 
-  EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+  } else {
+    std::vector<std::string> accounts_to_send = {account_id};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
 
   AccountReconcilor* reconcilor = GetMockReconcilor();
   reconcilor->StartReconcile();
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
 
   base::RunLoop().RunUntilIdle();
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id,
-                                      GoogleServiceAuthError::AuthErrorNone());
+
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id, GoogleServiceAuthError::AuthErrorNone());
+  } else {
+    SimulateSetAccountsInCookieCompleted(
+        reconcilor, GoogleServiceAuthError::AuthErrorNone());
+  }
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
-      signin_metrics::ACCOUNTS_SAME, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 1, 1);
+  if (!GetParam()) {
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
+        signin_metrics::ACCOUNTS_SAME, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 1, 1);
+  }
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileAddToCookieTwice) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+// Check that reconcile is aborted if there is token error on primary account.
+TEST_P(AccountReconcilorMirrorEndpointParamTest, TokenErrorOnPrimary) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
+  token_service()->UpdateAuthErrorForTesting(
+      account_id,
+      GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
+
+  cookie_manager_service()->SetListAccountsResponseTwoAccounts(
+      "user@gmail.com", "12345", "other@gmail.com", "67890");
+
+  AccountReconcilor* reconcilor = GetMockReconcilor();
+  reconcilor->StartReconcile();
+
+  base::RunLoop().RunUntilIdle();
+  ASSERT_FALSE(reconcilor->is_reconcile_started_);
+}
+
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+       StartReconcileAddToCookieTwice) {
+  const std::string account_id =
+      ConnectProfileToAccount("67890", "user@gmail.com");
   const std::string account_id2 =
-      PickAccountIdForAccount("67890", "other@gmail.com");
+      PickAccountIdForAccount("12345", "other@gmail.com");
   const std::string account_id3 =
       PickAccountIdForAccount("34567", "third@gmail.com");
 
   cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
-                                                              "12345");
+                                                              "67890");
   token_service()->UpdateCredentials(account_id2, "refresh_token");
 
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id3));
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id3));
+  } else {
+    std::vector<std::string> accounts_to_send = {account_id, account_id2};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
 
   AccountReconcilor* reconcilor = GetMockReconcilor();
   reconcilor->StartReconcile();
 
   base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id2,
-                                      GoogleServiceAuthError::AuthErrorNone());
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id2, GoogleServiceAuthError::AuthErrorNone());
+  } else {
+    SimulateSetAccountsInCookieCompleted(
+        reconcilor, GoogleServiceAuthError::AuthErrorNone());
+  }
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
-      signin_metrics::ACCOUNTS_SAME, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
+  if (!GetParam()) {
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
+        signin_metrics::ACCOUNTS_SAME, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
+  }
 
   // Do another pass after I've added a third account to the token service
   cookie_manager_service()->SetListAccountsResponseTwoAccounts(
-      "user@gmail.com", "12345", "other@gmail.com", "67890");
+      "user@gmail.com", "67890", "other@gmail.com", "12345");
   cookie_manager_service()->set_list_accounts_stale_for_testing(true);
 
   // This will cause the reconcilor to fire.
   token_service()->UpdateCredentials(account_id3, "refresh_token");
+  if (GetParam()) {
+    std::vector<std::string> accounts_to_send = {account_id, account_id2,
+                                                 account_id3};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
   base::RunLoop().RunUntilIdle();
 
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id3,
-                                      GoogleServiceAuthError::AuthErrorNone());
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id3, GoogleServiceAuthError::AuthErrorNone());
+  } else {
+    SimulateSetAccountsInCookieCompleted(
+        reconcilor, GoogleServiceAuthError::AuthErrorNone());
+  }
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
-      signin_metrics::ACCOUNTS_SAME, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.DifferentPrimaryAccounts.SubsequentRun",
-      signin_metrics::ACCOUNTS_SAME, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.AddedToCookieJar.SubsequentRun", 1, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.RemovedFromCookieJar.SubsequentRun", 0, 1);
+  if (!GetParam()) {
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
+        signin_metrics::ACCOUNTS_SAME, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.DifferentPrimaryAccounts.SubsequentRun",
+        signin_metrics::ACCOUNTS_SAME, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.AddedToCookieJar.SubsequentRun", 1, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.RemovedFromCookieJar.SubsequentRun", 0, 1);
+  }
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileBadPrimary) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileBadPrimary) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   const std::string account_id2 =
@@ -1724,33 +2027,45 @@
   cookie_manager_service()->SetListAccountsResponseTwoAccounts(
       "other@gmail.com", "67890", "user@gmail.com", "12345");
 
-  EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
+  } else {
+    std::vector<std::string> accounts_to_send = {account_id, account_id2};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
 
   AccountReconcilor* reconcilor = GetMockReconcilor();
   reconcilor->StartReconcile();
 
   base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id2,
-                                      GoogleServiceAuthError::AuthErrorNone());
-  ASSERT_TRUE(reconcilor->is_reconcile_started_);
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id,
-                                      GoogleServiceAuthError::AuthErrorNone());
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id2, GoogleServiceAuthError::AuthErrorNone());
+    ASSERT_TRUE(reconcilor->is_reconcile_started_);
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id, GoogleServiceAuthError::AuthErrorNone());
+  } else {
+    SimulateSetAccountsInCookieCompleted(
+        reconcilor, GoogleServiceAuthError::AuthErrorNone());
+  }
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
-      signin_metrics::COOKIE_AND_TOKEN_PRIMARIES_DIFFERENT, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1);
-  histogram_tester()->ExpectUniqueSample(
-      "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
+  if (!GetParam()) {
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.DifferentPrimaryAccounts.FirstRun",
+        signin_metrics::COOKIE_AND_TOKEN_PRIMARIES_DIFFERENT, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.AddedToCookieJar.FirstRun", 0, 1);
+    histogram_tester()->ExpectUniqueSample(
+        "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
+  }
 }
 
-TEST_F(AccountReconcilorTest, StartReconcileOnlyOnce) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, StartReconcileOnlyOnce) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
@@ -1767,8 +2082,7 @@
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 }
 
-TEST_F(AccountReconcilorTest, Lock) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, Lock) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
@@ -1869,15 +2183,21 @@
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 }
 
-TEST_F(AccountReconcilorTest, AddAccountToCookieCompletedWithBogusAccount) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest,
+       AddAccountToCookieCompletedWithBogusAccount) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
       {"user@gmail.com", "12345", false /* valid */, false /* signed_out */,
        true /* verified */});
 
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
+  } else {
+    std::vector<std::string> accounts_to_send = {account_id};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
 
   AccountReconcilor* reconcilor = GetMockReconcilor();
   ASSERT_TRUE(reconcilor);
@@ -1889,17 +2209,18 @@
   base::RunLoop().RunUntilIdle();
 
   // If an unknown account id is sent, it should not upset the state.
-  SimulateAddAccountToCookieCompleted(reconcilor, "bogus_account_id",
-                                      GoogleServiceAuthError::AuthErrorNone());
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
-
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id,
-                                      GoogleServiceAuthError::AuthErrorNone());
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id, GoogleServiceAuthError::AuthErrorNone());
+  } else {
+    SimulateSetAccountsInCookieCompleted(
+        reconcilor, GoogleServiceAuthError::AuthErrorNone());
+  }
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
 }
 
-TEST_F(AccountReconcilorTest, NoLoopWithBadPrimary) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, NoLoopWithBadPrimary) {
   // Connect profile to a primary account and then add a secondary account.
   const std::string account_id1 =
       ConnectProfileToAccount("12345", "user@gmail.com");
@@ -1907,10 +2228,15 @@
       PickAccountIdForAccount("67890", "other@gmail.com");
   token_service()->UpdateCredentials(account_id2, "refresh_token");
 
-  EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1));
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
-
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1));
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
+  } else {
+    std::vector<std::string> accounts_to_send = {account_id1, account_id2};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
   // The primary account is in auth error, so it is not in the cookie.
   cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
       {"other@gmail.com", "67890", false /* valid */, false /* signed_out */,
@@ -1927,9 +2253,13 @@
       GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
 
   // The primary cannot be added to cookie, so it fails.
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id1, error);
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id2,
-                                      GoogleServiceAuthError::AuthErrorNone());
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(reconcilor, account_id1, error);
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id2, GoogleServiceAuthError::AuthErrorNone());
+  } else {
+    SimulateSetAccountsInCookieCompleted(reconcilor, error);
+  }
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
   ASSERT_NE(GoogleServiceAuthError::State::NONE,
@@ -1947,8 +2277,7 @@
   testing::Mock::VerifyAndClearExpectations(GetMockReconcilor());
 }
 
-TEST_F(AccountReconcilorTest, WontMergeAccountsWithError) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, WontMergeAccountsWithError) {
   // Connect profile to a primary account and then add a secondary account.
   const std::string account_id1 =
       ConnectProfileToAccount("12345", "user@gmail.com");
@@ -1967,7 +2296,13 @@
   // Since the cookie jar starts empty, the reconcilor should attempt to merge
   // accounts into it.  However, it should only try accounts not in auth
   // error state.
-  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1));
+  if (!GetParam()) {
+    EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id1));
+  } else {
+    std::vector<std::string> accounts_to_send = {account_id1};
+    EXPECT_CALL(*GetMockReconcilor(),
+                PerformSetCookiesAction(accounts_to_send));
+  }
 
   AccountReconcilor* reconcilor = GetMockReconcilor();
   ASSERT_TRUE(reconcilor);
@@ -1976,8 +2311,13 @@
   base::RunLoop().RunUntilIdle();
   ASSERT_TRUE(reconcilor->is_reconcile_started_);
 
-  SimulateAddAccountToCookieCompleted(reconcilor, account_id1,
-                                      GoogleServiceAuthError::AuthErrorNone());
+  if (!GetParam()) {
+    SimulateAddAccountToCookieCompleted(
+        reconcilor, account_id1, GoogleServiceAuthError::AuthErrorNone());
+  } else {
+    SimulateSetAccountsInCookieCompleted(
+        reconcilor, GoogleServiceAuthError::AuthErrorNone());
+  }
   base::RunLoop().RunUntilIdle();
   ASSERT_FALSE(reconcilor->is_reconcile_started_);
   ASSERT_EQ(GoogleServiceAuthError::State::NONE,
@@ -2010,8 +2350,7 @@
 
 // Test that delegate timeout is not called when the delegate does not offer a
 // valid timeout.
-TEST_F(AccountReconcilorTest, DelegateTimeoutIsNotCalled) {
-  SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+TEST_P(AccountReconcilorMirrorEndpointParamTest, DelegateTimeoutIsNotCalled) {
   ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
                                                               "12345");
@@ -2026,6 +2365,10 @@
   EXPECT_FALSE(timer->IsRunning());
 }
 
+INSTANTIATE_TEST_CASE_P(TestEndpoint,
+                        AccountReconcilorMirrorEndpointParamTest,
+                        ::testing::ValuesIn({false, true}));
+
 TEST_F(AccountReconcilorTest, DelegateTimeoutIsNotCalledIfTimeoutIsNotReached) {
   ConnectProfileToAccount("12345", "user@gmail.com");
   cookie_manager_service()->SetListAccountsResponseOneAccount("user@gmail.com",
@@ -2047,4 +2390,4 @@
   EXPECT_EQ(0, spy_delegate->num_reconcile_timeout_calls_);
   EXPECT_EQ(1, spy_delegate->num_reconcile_finished_calls_);
   EXPECT_FALSE(reconcilor->is_reconcile_started_);
-}
+}
\ No newline at end of file
diff --git a/components/signin/core/browser/mirror_account_reconcilor_delegate.cc b/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
index 519c572..ed10c7c2 100644
--- a/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
+++ b/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
@@ -49,6 +49,39 @@
   return primary_account;
 }
 
+bool MirrorAccountReconcilorDelegate::ReorderChromeAccountsForReconcileIfNeeded(
+    const std::vector<std::string>& chrome_accounts,
+    const std::string primary_account,
+    const std::vector<gaia::ListedAccount>& gaia_accounts,
+    std::vector<std::string>* accounts_to_send) const {
+  DCHECK(accounts_to_send);
+  accounts_to_send->clear();
+  accounts_to_send->reserve(chrome_accounts.size());
+  bool needs_reordering = false;
+
+  DCHECK(!primary_account.empty());
+  accounts_to_send->push_back(primary_account);
+
+  for (const std::string& chrome_account : chrome_accounts) {
+    if (chrome_account == primary_account)
+      continue;
+    accounts_to_send->push_back(chrome_account);
+  }
+
+  if (gaia_accounts.size() != accounts_to_send->size()) {
+    needs_reordering = true;
+  } else {
+    for (size_t i = 0; i < accounts_to_send->size(); ++i) {
+      const gaia::ListedAccount& gaia_account = gaia_accounts[i];
+      if (gaia_account.id != accounts_to_send->at(i) || !gaia_account.valid) {
+        needs_reordering = true;
+        break;
+      }
+    }
+  }
+  return needs_reordering;
+}
+
 void MirrorAccountReconcilorDelegate::GoogleSigninSucceeded(
     const std::string& account_id,
     const std::string& username) {
diff --git a/components/signin/core/browser/mirror_account_reconcilor_delegate.h b/components/signin/core/browser/mirror_account_reconcilor_delegate.h
index 1a9e3c84..5be1d28 100644
--- a/components/signin/core/browser/mirror_account_reconcilor_delegate.h
+++ b/components/signin/core/browser/mirror_account_reconcilor_delegate.h
@@ -31,6 +31,12 @@
       bool first_execution,
       bool will_logout) const override;
 
+  bool ReorderChromeAccountsForReconcileIfNeeded(
+      const std::vector<std::string>& chrome_accounts,
+      const std::string primary_account,
+      const std::vector<gaia::ListedAccount>& gaia_accounts,
+      std::vector<std::string>* accounts_to_send) const override;
+
   // SigninManagerBase::Observer:
   void GoogleSigninSucceeded(const std::string& account_id,
                              const std::string& username) override;
diff --git a/components/sync/base/pref_names.cc b/components/sync/base/pref_names.cc
index 712c0fa..be1c5fd 100644
--- a/components/sync/base/pref_names.cc
+++ b/components/sync/base/pref_names.cc
@@ -90,10 +90,6 @@
 const char kSyncKeystoreEncryptionBootstrapToken[] =
     "sync.keystore_encryption_bootstrap_token";
 
-// The GUID session sync will use to identify this client, even across sync
-// disable/enable events.
-const char kSyncSessionsGUID[] = "sync.session_sync_guid";
-
 #if defined(OS_CHROMEOS)
 // A string that is used to store first-time sync startup after once sync is
 // disabled. This will be refreshed every sign-in.
diff --git a/components/sync/base/pref_names.h b/components/sync/base/pref_names.h
index a1f9300..3999182 100644
--- a/components/sync/base/pref_names.h
+++ b/components/sync/base/pref_names.h
@@ -64,8 +64,6 @@
 extern const char kSyncEncryptionBootstrapToken[];
 extern const char kSyncKeystoreEncryptionBootstrapToken[];
 
-extern const char kSyncSessionsGUID[];
-
 #if defined(OS_CHROMEOS)
 extern const char kSyncSpareBootstrapToken[];
 #endif  // defined(OS_CHROMEOS)
diff --git a/components/sync/base/sync_prefs.cc b/components/sync/base/sync_prefs.cc
index 7b427ad..38fb56b 100644
--- a/components/sync/base/sync_prefs.cc
+++ b/components/sync/base/sync_prefs.cc
@@ -64,8 +64,6 @@
 
 }  // namespace
 
-SessionSyncPrefs::~SessionSyncPrefs() {}
-
 CryptoSyncPrefs::~CryptoSyncPrefs() {}
 
 SyncPrefObserver::~SyncPrefObserver() {}
@@ -130,7 +128,6 @@
 #endif
 
   registry->RegisterBooleanPref(prefs::kSyncHasAuthError, false);
-  registry->RegisterStringPref(prefs::kSyncSessionsGUID, std::string());
   registry->RegisterBooleanPref(prefs::kSyncPassphrasePrompted, false);
   registry->RegisterIntegerPref(prefs::kSyncMemoryPressureWarningCount, -1);
   registry->RegisterBooleanPref(prefs::kSyncShutdownCleanly, false);
@@ -322,16 +319,6 @@
   pref_service_->SetString(prefs::kSyncKeystoreEncryptionBootstrapToken, token);
 }
 
-std::string SyncPrefs::GetSyncSessionsGUID() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  return pref_service_->GetString(prefs::kSyncSessionsGUID);
-}
-
-void SyncPrefs::SetSyncSessionsGUID(const std::string& guid) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  pref_service_->SetString(prefs::kSyncSessionsGUID, guid);
-}
-
 // static
 const char* SyncPrefs::GetPrefNameForDataType(ModelType type) {
   switch (type) {
diff --git a/components/sync/base/sync_prefs.h b/components/sync/base/sync_prefs.h
index fddc65e..645f442 100644
--- a/components/sync/base/sync_prefs.h
+++ b/components/sync/base/sync_prefs.h
@@ -40,15 +40,6 @@
   virtual ~SyncPrefObserver();
 };
 
-// Use this for the unique machine tag used for session sync.
-class SessionSyncPrefs {
- public:
-  virtual ~SessionSyncPrefs();
-
-  virtual std::string GetSyncSessionsGUID() const = 0;
-  virtual void SetSyncSessionsGUID(const std::string& guid) = 0;
-};
-
 // Use this for crypto/passphrase-related parts of sync prefs.
 class CryptoSyncPrefs {
  public:
@@ -90,8 +81,7 @@
 //   sync_setup_wizard.cc
 //   sync_setup_wizard_unittest.cc
 //   two_client_preferences_sync_test.cc
-class SyncPrefs : public SessionSyncPrefs,
-                  public CryptoSyncPrefs,
+class SyncPrefs : public CryptoSyncPrefs,
                   public base::SupportsWeakPtr<SyncPrefs> {
  public:
   // |pref_service| may not be null.
@@ -178,10 +168,6 @@
   std::string GetKeystoreEncryptionBootstrapToken() const override;
   void SetKeystoreEncryptionBootstrapToken(const std::string& token) override;
 
-  // Use this for the unique machine tag used for session sync.
-  std::string GetSyncSessionsGUID() const override;
-  void SetSyncSessionsGUID(const std::string& guid) override;
-
   // Maps |type| to its corresponding preference name.
   static const char* GetPrefNameForDataType(ModelType type);
 
diff --git a/components/sync/driver/fake_sync_client.cc b/components/sync/driver/fake_sync_client.cc
index 012d402..b6c0b94 100644
--- a/components/sync/driver/fake_sync_client.cc
+++ b/components/sync/driver/fake_sync_client.cc
@@ -59,6 +59,10 @@
   return nullptr;
 }
 
+sync_sessions::SessionSyncService* FakeSyncClient::GetSessionSyncService() {
+  return nullptr;
+}
+
 bool FakeSyncClient::HasPasswordStore() {
   return false;
 }
@@ -90,10 +94,6 @@
   return scoped_refptr<ExtensionsActivity>();
 }
 
-sync_sessions::SyncSessionsClient* FakeSyncClient::GetSyncSessionsClient() {
-  return nullptr;
-}
-
 base::WeakPtr<SyncableService> FakeSyncClient::GetSyncableServiceForType(
     ModelType type) {
   return base::WeakPtr<SyncableService>();
diff --git a/components/sync/driver/fake_sync_client.h b/components/sync/driver/fake_sync_client.h
index 3765d75..ff38e989 100644
--- a/components/sync/driver/fake_sync_client.h
+++ b/components/sync/driver/fake_sync_client.h
@@ -31,6 +31,7 @@
   bookmarks::BookmarkModel* GetBookmarkModel() override;
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
+  sync_sessions::SessionSyncService* GetSessionSyncService() override;
   bool HasPasswordStore() override;
   base::Closure GetPasswordStateChangedCallback() override;
   DataTypeController::TypeVector CreateDataTypeControllers(
@@ -39,7 +40,6 @@
   BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
   invalidation::InvalidationService* GetInvalidationService() override;
   scoped_refptr<ExtensionsActivity> GetExtensionsActivity() override;
-  sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override;
   base::WeakPtr<SyncableService> GetSyncableServiceForType(
       ModelType type) override;
   base::WeakPtr<ModelTypeControllerDelegate> GetControllerDelegateForModelType(
diff --git a/components/sync/driver/fake_sync_service.cc b/components/sync/driver/fake_sync_service.cc
index 1c070842..53641a9 100644
--- a/components/sync/driver/fake_sync_service.cc
+++ b/components/sync/driver/fake_sync_service.cc
@@ -206,10 +206,6 @@
 void FakeSyncService::GetAllNodes(
     const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback) {}
 
-GlobalIdMapper* FakeSyncService::GetGlobalIdMapper() const {
-  return nullptr;
-}
-
 bool FakeSyncService::IsPassphraseRequired() const {
   return false;
 }
diff --git a/components/sync/driver/fake_sync_service.h b/components/sync/driver/fake_sync_service.h
index 5798382..5bb5898 100644
--- a/components/sync/driver/fake_sync_service.h
+++ b/components/sync/driver/fake_sync_service.h
@@ -88,7 +88,6 @@
   base::WeakPtr<JsController> GetJsController() override;
   void GetAllNodes(const base::Callback<void(std::unique_ptr<base::ListValue>)>&
                        callback) override;
-  GlobalIdMapper* GetGlobalIdMapper() const override;
 
   // DataTypeEncryptionHandler implementation.
   bool IsPassphraseRequired() const override;
diff --git a/components/sync/driver/sync_client.h b/components/sync/driver/sync_client.h
index 9a87945..203bc88 100644
--- a/components/sync/driver/sync_client.h
+++ b/components/sync/driver/sync_client.h
@@ -39,7 +39,7 @@
 }  // namespace invalidation
 
 namespace sync_sessions {
-class SyncSessionsClient;
+class SessionSyncService;
 }  // namespace sync_sessions
 
 namespace syncer {
@@ -76,6 +76,7 @@
   virtual bookmarks::BookmarkModel* GetBookmarkModel() = 0;
   virtual favicon::FaviconService* GetFaviconService() = 0;
   virtual history::HistoryService* GetHistoryService() = 0;
+  virtual sync_sessions::SessionSyncService* GetSessionSyncService() = 0;
   virtual bool HasPasswordStore() = 0;
 
   // Returns a vector with all supported datatypes and their controllers.
@@ -92,7 +93,6 @@
   virtual BookmarkUndoService* GetBookmarkUndoServiceIfExists() = 0;
   virtual invalidation::InvalidationService* GetInvalidationService() = 0;
   virtual scoped_refptr<ExtensionsActivity> GetExtensionsActivity() = 0;
-  virtual sync_sessions::SyncSessionsClient* GetSyncSessionsClient() = 0;
 
   // Returns a weak pointer to the syncable service specified by |type|.
   // Weak pointer may be unset if service is already destroyed.
diff --git a/components/sync/driver/sync_client_mock.h b/components/sync/driver/sync_client_mock.h
index 6e27bed..221e986 100644
--- a/components/sync/driver/sync_client_mock.h
+++ b/components/sync/driver/sync_client_mock.h
@@ -24,6 +24,7 @@
   MOCK_METHOD0(GetFaviconService, favicon::FaviconService*());
   MOCK_METHOD0(GetHistoryService, history::HistoryService*());
   MOCK_METHOD0(HasPasswordStore, bool());
+  MOCK_METHOD0(GetSessionSyncService, sync_sessions::SessionSyncService*());
   MOCK_METHOD1(CreateDataTypeControllers,
                DataTypeController::TypeVector(
                    LocalDeviceInfoProvider* local_device_info_provider));
@@ -33,7 +34,6 @@
   MOCK_METHOD0(GetBookmarkUndoServiceIfExists, BookmarkUndoService*());
   MOCK_METHOD0(GetInvalidationService, invalidation::InvalidationService*());
   MOCK_METHOD0(GetExtensionsActivity, scoped_refptr<ExtensionsActivity>());
-  MOCK_METHOD0(GetSyncSessionsClient, sync_sessions::SyncSessionsClient*());
   MOCK_METHOD1(GetSyncableServiceForType,
                base::WeakPtr<SyncableService>(ModelType type));
   MOCK_METHOD1(GetControllerDelegateForModelType,
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index 7a19975..0277215 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -30,7 +30,6 @@
 
 class BaseTransaction;
 class JsController;
-class GlobalIdMapper;
 class ProtocolEventObserver;
 class SyncClient;
 class SyncCycleSnapshot;
@@ -384,9 +383,6 @@
   // function.
   virtual UserShare* GetUserShare() const = 0;
 
-  // TODO(crbug.com/865936): Move this down into ProfileSyncService.
-  virtual GlobalIdMapper* GetGlobalIdMapper() const = 0;
-
   //////////////////////////////////////////////////////////////////////////////
   // DETAILED STATE FOR DEBUG UI
   //////////////////////////////////////////////////////////////////////////////
diff --git a/components/sync/engine_impl/uss_migrator.cc b/components/sync/engine_impl/uss_migrator.cc
index 55d407c..9e1e69b 100644
--- a/components/sync/engine_impl/uss_migrator.cc
+++ b/components/sync/engine_impl/uss_migrator.cc
@@ -48,16 +48,21 @@
   if (!entry.GetServerParentId().IsNull()) {
     entity->set_parent_id_string(entry.GetServerParentId().GetServerId());
   }
-  if (entry.GetServerUniquePosition().IsValid()) {
+
+  if (!entry.GetUniqueServerTag().empty()) {
+    // Permanent nodes don't have unique_positions and are assigned unique
+    // server tags.
+    entity->set_server_defined_unique_tag(entry.GetUniqueServerTag());
+  } else if (entry.GetServerUniquePosition().IsValid()) {
     *entity->mutable_unique_position() =
         entry.GetServerUniquePosition().ToProto();
   } else {
-    // All boookmarks should have valid unique_positions including legacy
-    // bookmarks that are missing the field. Directory should have taken care of
-    // assigning proper unique_position during the first sync flow.
+    // All boookmarks (except permanent ones with server tag) should have valid
+    // unique_positions including legacy bookmarks that are missing the field.
+    // Directory should have taken care of assigning proper unique_position
+    // during the first sync flow.
     DCHECK_NE(BOOKMARKS, type);
   }
-  entity->set_server_defined_unique_tag(entry.GetUniqueServerTag());
 
   // It looks like there are fancy other ways to get e.g. passwords specifics
   // out of Entry. Do we need to special-case them when we ship those types?
@@ -65,6 +70,20 @@
   return true;
 }
 
+void AppendAllDescendantIds(const ReadTransaction* trans,
+                            const ReadNode& node,
+                            std::vector<int64_t>* all_descendant_ids) {
+  std::vector<int64_t> child_ids;
+  node.GetChildIds(&child_ids);
+
+  for (int child_id : child_ids) {
+    all_descendant_ids->push_back(child_id);
+    ReadNode child(trans);
+    child.InitByIdLookup(child_id);
+    AppendAllDescendantIds(trans, child, all_descendant_ids);
+  }
+}
+
 }  // namespace
 
 bool MigrateDirectoryData(ModelType type,
@@ -96,7 +115,7 @@
                                             &context);
 
   std::vector<int64_t> child_ids;
-  root.GetChildIds(&child_ids);
+  AppendAllDescendantIds(&trans, root, &child_ids);
 
   // Process |batch_size| entities at a time to reduce memory usage.
   size_t i = 0;
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor.cc b/components/sync/model_impl/client_tag_based_model_type_processor.cc
index a2ff46a5..68f6f2e 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor.cc
@@ -776,8 +776,12 @@
       // Squash the pending commit.
       entity->RecordForcedUpdate(update);
       // Update client data to match server.
-      changes->push_back(
-          EntityChange::CreateUpdate(entity->storage_key(), update.entity));
+      if (update.entity->is_deleted()) {
+        changes->push_back(EntityChange::CreateDelete(entity->storage_key()));
+      } else {
+        changes->push_back(
+            EntityChange::CreateUpdate(entity->storage_key(), update.entity));
+      }
       break;
     case ConflictResolution::USE_NEW:
       // Record that we received the update.
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
index 99025bed..d12beaa 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -1216,6 +1216,20 @@
 }
 
 TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldResolveConflictToRemoteDeletion) {
+  InitializeToReadyState();
+  bridge()->WriteItem(kKey1, kValue1);
+  bridge()->SetConflictResolution(ConflictResolution::UseRemote());
+  worker()->TombstoneFromServer(kHash1);
+
+  // Updated client data and metadata; no new commit request.
+  EXPECT_EQ(0U, db().data_count());
+  EXPECT_EQ(0U, db().metadata_count());
+  EXPECT_EQ(2U, db().data_change_count());
+  EXPECT_EQ(2U, db().metadata_change_count());
+}
+
+TEST_F(ClientTagBasedModelTypeProcessorTest,
        ShouldResolveConflictToNewVersion) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn
index 7be002c27..57f9057 100644
--- a/components/sync_sessions/BUILD.gn
+++ b/components/sync_sessions/BUILD.gn
@@ -25,6 +25,10 @@
     "session_store.h",
     "session_sync_bridge.cc",
     "session_sync_bridge.h",
+    "session_sync_prefs.cc",
+    "session_sync_prefs.h",
+    "session_sync_service.cc",
+    "session_sync_service.h",
     "sessions_global_id_mapper.cc",
     "sessions_global_id_mapper.h",
     "sessions_sync_manager.cc",
@@ -56,8 +60,10 @@
     "//components/bookmarks/browser",
     "//components/favicon/core",
     "//components/history/core/browser",
+    "//components/keyed_service/core",
     "//components/prefs",
     "//components/variations",
+    "//components/version_info",
     "//ui/base:base",
     "//ui/gfx",
     "//url",
diff --git a/components/sync_sessions/DEPS b/components/sync_sessions/DEPS
index 564d4219..9ce25856 100644
--- a/components/sync_sessions/DEPS
+++ b/components/sync_sessions/DEPS
@@ -2,10 +2,12 @@
   "+components/bookmarks/browser",
   "+components/favicon/core",
   "+components/history/core/browser",
+  "+components/keyed_service/core",
   "+components/prefs",
   "+components/sessions",
   "+components/sync",
   "+components/variations",
+  "+components/version_info",
   "+ui/base/page_transition_types.h",
   "+ui/gfx",
 ]
diff --git a/components/sync_sessions/mock_sync_sessions_client.h b/components/sync_sessions/mock_sync_sessions_client.h
index 33b301cd..0492dee1 100644
--- a/components/sync_sessions/mock_sync_sessions_client.h
+++ b/components/sync_sessions/mock_sync_sessions_client.h
@@ -19,10 +19,14 @@
 
   MOCK_METHOD0(GetFaviconService, favicon::FaviconService*());
   MOCK_METHOD0(GetHistoryService, history::HistoryService*());
+  MOCK_METHOD0(GetSessionSyncPrefs, SessionSyncPrefs*());
+  MOCK_METHOD0(GetStoreFactory, syncer::RepeatingModelTypeStoreFactory());
   MOCK_METHOD0(GetLocalDeviceInfo, const syncer::DeviceInfo*());
   MOCK_CONST_METHOD1(ShouldSyncURL, bool(const GURL& url));
   MOCK_METHOD0(GetSyncedWindowDelegatesGetter, SyncedWindowDelegatesGetter*());
   MOCK_METHOD0(GetLocalSessionEventRouter, LocalSessionEventRouter*());
+  MOCK_METHOD0(IsProxyTabsSyncRunning, bool());
+  MOCK_METHOD0(NotifyForeignSessionUpdated, void());
 };
 
 }  // namespace sync_sessions
diff --git a/components/sync_sessions/session_store.cc b/components/sync_sessions/session_store.cc
index 2431884..2e8dfc2 100644
--- a/components/sync_sessions/session_store.cc
+++ b/components/sync_sessions/session_store.cc
@@ -16,7 +16,6 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/pickle.h"
 #include "base/strings/stringprintf.h"
-#include "components/sync/base/sync_prefs.h"
 #include "components/sync/base/time.h"
 #include "components/sync/device_info/device_info.h"
 #include "components/sync/device_info/device_info_util.h"
@@ -25,6 +24,7 @@
 #include "components/sync/model/mutable_data_batch.h"
 #include "components/sync/protocol/model_type_state.pb.h"
 #include "components/sync/protocol/sync.pb.h"
+#include "components/sync_sessions/session_sync_prefs.h"
 #include "components/sync_sessions/sync_sessions_client.h"
 
 namespace sync_sessions {
@@ -77,7 +77,8 @@
 }
 
 std::string GetSessionTagWithPrefs(const std::string& cache_guid,
-                                   syncer::SessionSyncPrefs* sync_prefs) {
+                                   SessionSyncPrefs* sync_prefs) {
+  DCHECK(sync_prefs);
   const std::string persisted_guid = sync_prefs->GetSyncSessionsGUID();
   if (!persisted_guid.empty()) {
     DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid;
@@ -102,17 +103,11 @@
  public:
   // Raw pointers must not be null and must outlive this object.
   FactoryImpl(SyncSessionsClient* sessions_client,
-              syncer::SessionSyncPrefs* sync_prefs,
-              const syncer::RepeatingModelTypeStoreFactory& store_factory,
               const SessionStore::RestoredForeignTabCallback&
                   restored_foreign_tab_callback)
       : sessions_client_(sessions_client),
-        sync_prefs_(sync_prefs),
-        store_factory_(store_factory),
         restored_foreign_tab_callback_(restored_foreign_tab_callback) {
     DCHECK(sessions_client);
-    DCHECK(sync_prefs);
-    DCHECK(store_factory_);
   }
 
   ~FactoryImpl() {}
@@ -125,11 +120,12 @@
     SessionStore::SessionInfo session_info;
     session_info.client_name = device_info.client_name();
     session_info.device_type = device_info.device_type();
-    session_info.session_tag = GetSessionTagWithPrefs(cache_guid, sync_prefs_);
+    session_info.session_tag = GetSessionTagWithPrefs(
+        cache_guid, sessions_client_->GetSessionSyncPrefs());
 
     DVLOG(1) << "Initiating creation of session store";
 
-    store_factory_.Run(
+    sessions_client_->GetStoreFactory().Run(
         syncer::SESSIONS,
         base::BindOnce(&FactoryImpl::OnStoreCreated, base::AsWeakPtr(this),
                        session_info, std::move(callback)));
@@ -204,8 +200,6 @@
   }
 
   SyncSessionsClient* const sessions_client_;
-  syncer::SessionSyncPrefs* const sync_prefs_;
-  const syncer::RepeatingModelTypeStoreFactory store_factory_;
   const SessionStore::RestoredForeignTabCallback restored_foreign_tab_callback_;
 };
 
@@ -214,12 +208,9 @@
 // static
 SessionStore::Factory SessionStore::CreateFactory(
     SyncSessionsClient* sessions_client,
-    syncer::SessionSyncPrefs* sync_prefs,
-    const syncer::RepeatingModelTypeStoreFactory& store_factory,
     const RestoredForeignTabCallback& restored_foreign_tab_callback) {
-  auto factory =
-      std::make_unique<FactoryImpl>(sessions_client, sync_prefs, store_factory,
-                                    restored_foreign_tab_callback);
+  auto factory = std::make_unique<FactoryImpl>(sessions_client,
+                                               restored_foreign_tab_callback);
   return base::BindRepeating(&FactoryImpl::Create, std::move(factory));
 }
 
diff --git a/components/sync_sessions/session_store.h b/components/sync_sessions/session_store.h
index 9b4675f..db274633 100644
--- a/components/sync_sessions/session_store.h
+++ b/components/sync_sessions/session_store.h
@@ -21,7 +21,6 @@
 
 namespace syncer {
 class DeviceInfo;
-class SessionSyncPrefs;
 }  // namespace syncer
 
 namespace sync_sessions {
@@ -53,12 +52,10 @@
       base::RepeatingCallback<void(const sync_pb::SessionTab&, base::Time)>;
 
   // Creates a factory object that is capable of constructing instances of type
-  // |SessionStore| and handling the involved IO. All pointer arguments must not
-  // be null and must outlive the factory as well as the instantiated stores.
+  // |SessionStore| and handling the involved IO. |sessions_client| must not be
+  // null and must outlive the factory as well as the instantiated stores.
   static Factory CreateFactory(
       SyncSessionsClient* sessions_client,
-      syncer::SessionSyncPrefs* sync_prefs,
-      const syncer::RepeatingModelTypeStoreFactory& store_factory,
       const RestoredForeignTabCallback& restored_foreign_tab_callback);
 
   // Verifies whether a proto is malformed (e.g. required fields are missing).
diff --git a/components/sync_sessions/session_store_unittest.cc b/components/sync_sessions/session_store_unittest.cc
index d1fa2df9..2a4aab80 100644
--- a/components/sync_sessions/session_store_unittest.cc
+++ b/components/sync_sessions/session_store_unittest.cc
@@ -12,13 +12,14 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/test/mock_callback.h"
+#include "components/prefs/testing_pref_service.h"
 #include "components/sync/base/hash_util.h"
-#include "components/sync/base/sync_prefs.h"
 #include "components/sync/device_info/device_info.h"
 #include "components/sync/model/model_type_store_test_util.h"
 #include "components/sync/protocol/session_specifics.pb.h"
 #include "components/sync/test/test_matchers.h"
 #include "components/sync_sessions/mock_sync_sessions_client.h"
+#include "components/sync_sessions/session_sync_prefs.h"
 #include "components/sync_sessions/test_matchers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -51,15 +52,6 @@
 const char kCacheGuid[] = "SomeCacheGuid";
 const char kClientName[] = "Some Client Name";
 
-class MockSessionSyncPrefs : public syncer::SessionSyncPrefs {
- public:
-  MockSessionSyncPrefs() = default;
-  ~MockSessionSyncPrefs() override = default;
-
-  MOCK_CONST_METHOD0(GetSyncSessionsGUID, std::string());
-  MOCK_METHOD1(SetSyncSessionsGUID, void(const std::string& guid));
-};
-
 // A mock callback that a) can be used as mock to verify call expectations and
 // b) conveniently exposes the last instantiated session store.
 class MockFactoryCompletionCallback {
@@ -169,22 +161,30 @@
                            "Chrome 10k",
                            sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
                            "device_id"),
+        session_sync_prefs_(&pref_service_),
         underlying_store_(
             syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest(
-                syncer::SESSIONS)),
-        factory_(SessionStore::CreateFactory(
-            &mock_sync_sessions_client_,
-            &mock_sync_prefs_,
-            syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore(
-                underlying_store_.get()),
-            mock_restored_foreign_tab_callback_.Get())) {}
+                syncer::SESSIONS)) {
+    SessionSyncPrefs::RegisterProfilePrefs(pref_service_.registry());
+
+    ON_CALL(mock_sync_sessions_client_, GetSessionSyncPrefs())
+        .WillByDefault(Return(&session_sync_prefs_));
+    ON_CALL(mock_sync_sessions_client_, GetStoreFactory())
+        .WillByDefault(
+            Return(syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore(
+                underlying_store_.get())));
+
+    factory_ = SessionStore::CreateFactory(
+        &mock_sync_sessions_client_, mock_restored_foreign_tab_callback_.Get());
+  }
 
   ~SessionStoreFactoryTest() override {}
 
   base::MessageLoop message_loop_;
   const syncer::DeviceInfo local_device_info_;
+  TestingPrefServiceSimple pref_service_;
+  SessionSyncPrefs session_sync_prefs_;
   testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_;
-  testing::NiceMock<MockSessionSyncPrefs> mock_sync_prefs_;
   testing::NiceMock<
       base::MockCallback<SessionStore::RestoredForeignTabCallback>>
       mock_restored_foreign_tab_callback_;
@@ -194,9 +194,7 @@
 };
 
 TEST_F(SessionStoreFactoryTest, ShouldCreateStore) {
-  EXPECT_CALL(mock_sync_prefs_, GetSyncSessionsGUID());
-  EXPECT_CALL(mock_sync_prefs_,
-              SetSyncSessionsGUID(std::string("session_sync") + kCacheGuid));
+  ASSERT_THAT(session_sync_prefs_.GetSyncSessionsGUID(), IsEmpty());
 
   MockFactoryCompletionCallback completion;
   EXPECT_CALL(completion, Run(NoModelError(), /*store=*/NotNull(),
@@ -206,13 +204,13 @@
   ASSERT_THAT(completion.GetResult(), NotNull());
   EXPECT_THAT(completion.GetResult()->local_session_info().client_name,
               Eq(kClientName));
+  EXPECT_THAT(session_sync_prefs_.GetSyncSessionsGUID(),
+              Eq(std::string("session_sync") + kCacheGuid));
 }
 
 TEST_F(SessionStoreFactoryTest, ShouldReadSessionsGuidFromPrefs) {
   const std::string kCachedGuid = "cachedguid1";
-  EXPECT_CALL(mock_sync_prefs_, SetSyncSessionsGUID(_)).Times(0);
-  EXPECT_CALL(mock_sync_prefs_, GetSyncSessionsGUID())
-      .WillOnce(Return(kCachedGuid));
+  session_sync_prefs_.SetSyncSessionsGUID(kCachedGuid);
 
   NiceMock<MockFactoryCompletionCallback> completion;
   factory_.Run(local_device_info_, completion.Get());
@@ -220,6 +218,7 @@
   ASSERT_THAT(completion.GetResult(), NotNull());
   EXPECT_THAT(completion.GetResult()->local_session_info().session_tag,
               Eq(kCachedGuid));
+  EXPECT_THAT(session_sync_prefs_.GetSyncSessionsGUID(), Eq(kCachedGuid));
 }
 
 // Test fixture that creates an initial session store.
@@ -228,9 +227,7 @@
   const std::string kLocalSessionTag = "localsessiontag";
 
   SessionStoreTest() {
-    ON_CALL(mock_sync_prefs_, GetSyncSessionsGUID())
-        .WillByDefault(Return(kLocalSessionTag));
-
+    session_sync_prefs_.SetSyncSessionsGUID(kLocalSessionTag);
     session_store_ = CreateSessionStore();
   }
 
diff --git a/components/sync_sessions/session_sync_bridge.cc b/components/sync_sessions/session_sync_bridge.cc
index a336278..78e55cdd 100644
--- a/components/sync_sessions/session_sync_bridge.cc
+++ b/components/sync_sessions/session_sync_bridge.cc
@@ -102,28 +102,21 @@
 
 SessionSyncBridge::SessionSyncBridge(
     SyncSessionsClient* sessions_client,
-    syncer::SessionSyncPrefs* sync_prefs,
-    const syncer::RepeatingModelTypeStoreFactory& store_factory,
-    const base::RepeatingClosure& foreign_sessions_updated_callback,
     std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
     : ModelTypeSyncBridge(std::move(change_processor)),
       sessions_client_(sessions_client),
       local_session_event_router_(
           sessions_client->GetLocalSessionEventRouter()),
-      foreign_sessions_updated_callback_(foreign_sessions_updated_callback),
       favicon_cache_(sessions_client->GetFaviconService(),
                      sessions_client->GetHistoryService(),
                      kMaxSyncFavicons),
       session_store_factory_(SessionStore::CreateFactory(
           sessions_client,
-          sync_prefs,
-          store_factory,
           base::BindRepeating(&FaviconCache::UpdateMappingsFromForeignTab,
                               base::Unretained(&favicon_cache_)))),
       weak_ptr_factory_(this) {
   DCHECK(sessions_client_);
   DCHECK(local_session_event_router_);
-  DCHECK(foreign_sessions_updated_callback_);
 }
 
 SessionSyncBridge::~SessionSyncBridge() {
@@ -265,7 +258,7 @@
   SessionStore::WriteBatch::Commit(std::move(batch));
 
   if (!entity_changes.empty()) {
-    foreign_sessions_updated_callback_.Run();
+    sessions_client_->NotifyForeignSessionUpdated();
   }
 
   return base::nullopt;
@@ -346,18 +339,9 @@
 
   const syncer::DeviceInfo* device_info =
       sessions_client_->GetLocalDeviceInfo();
-  // DeviceInfo must be available by the time sync starts.
-  // TODO(crbug.com/867801): The DCHECKs later below should suffice but such
-  // condition is currently not guaranteed due to posting of tasks, which means
-  // |request| might be slightly stale if sync was disabled and re-enabled
-  // quickly. As a temporary mitigation, we report an error in this case.
-  if (!device_info || device_info->guid() != request.cache_guid) {
-    DLOG(WARNING) << "Stale datatype activation request, treating as error.";
-    change_processor()->ReportError(
-        syncer::ModelError(FROM_HERE, "Stale cache GUID"));
-    return;
-  }
 
+  // DeviceInfo must be available by the time sync starts, because there's no
+  // task posting involved in the sessions controller.
   DCHECK(device_info);
   DCHECK_EQ(device_info->guid(), request.cache_guid);
 
@@ -461,7 +445,7 @@
   change_processor()->Delete(header_storage_key,
                              batch->GetMetadataChangeList());
 
-  foreign_sessions_updated_callback_.Run();
+  sessions_client_->NotifyForeignSessionUpdated();
 }
 
 std::unique_ptr<SessionStore::WriteBatch>
diff --git a/components/sync_sessions/session_sync_bridge.h b/components/sync_sessions/session_sync_bridge.h
index de8af125..9c35134 100644
--- a/components/sync_sessions/session_sync_bridge.h
+++ b/components/sync_sessions/session_sync_bridge.h
@@ -43,9 +43,6 @@
   // Raw pointers must not be null and their pointees must outlive this object.
   SessionSyncBridge(
       SyncSessionsClient* sessions_client,
-      syncer::SessionSyncPrefs* sync_prefs,
-      const syncer::RepeatingModelTypeStoreFactory& store_factory,
-      const base::RepeatingClosure& foreign_sessions_updated_callback,
       std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
   ~SessionSyncBridge() override;
 
@@ -99,7 +96,6 @@
 
   SyncSessionsClient* const sessions_client_;
   LocalSessionEventRouter* const local_session_event_router_;
-  const base::RepeatingClosure foreign_sessions_updated_callback_;
 
   FaviconCache favicon_cache_;
   SessionsGlobalIdMapper global_id_mapper_;
diff --git a/components/sync_sessions/session_sync_bridge_unittest.cc b/components/sync_sessions/session_sync_bridge_unittest.cc
index 174ab8fd..916f2ef 100644
--- a/components/sync_sessions/session_sync_bridge_unittest.cc
+++ b/components/sync_sessions/session_sync_bridge_unittest.cc
@@ -15,7 +15,7 @@
 #include "base/run_loop.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/bind_test_util.h"
-#include "base/test/mock_callback.h"
+#include "components/prefs/testing_pref_service.h"
 #include "components/sync/base/hash_util.h"
 #include "components/sync/base/sync_prefs.h"
 #include "components/sync/device_info/device_info.h"
@@ -33,6 +33,7 @@
 #include "components/sync/test/test_matchers.h"
 #include "components/sync_sessions/favicon_cache.h"
 #include "components/sync_sessions/mock_sync_sessions_client.h"
+#include "components/sync_sessions/session_sync_prefs.h"
 #include "components/sync_sessions/tab_node_pool.h"
 #include "components/sync_sessions/test_matchers.h"
 #include "components/sync_sessions/test_synced_window_delegates_getter.h"
@@ -71,15 +72,6 @@
 
 const char kLocalSessionTag[] = "sessiontag1";
 
-class MockSessionSyncPrefs : public syncer::SessionSyncPrefs {
- public:
-  MockSessionSyncPrefs() = default;
-  ~MockSessionSyncPrefs() override = default;
-
-  MOCK_CONST_METHOD0(GetSyncSessionsGUID, std::string());
-  MOCK_METHOD1(SetSyncSessionsGUID, void(const std::string& guid));
-};
-
 MATCHER_P(EntityDataHasSpecifics, session_specifics_matcher, "") {
   return session_specifics_matcher.MatchAndExplain(arg->specifics.session(),
                                                    result_listener);
@@ -174,17 +166,26 @@
                            "device_id"),
         store_(syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest(
             syncer::SESSIONS)),
+        session_sync_prefs_(&pref_service_),
         favicon_cache_(/*favicon_service=*/nullptr,
                        /*history_service=*/nullptr,
                        /*max_sync_favicon_limit=*/0) {
+    SessionSyncPrefs::RegisterProfilePrefs(pref_service_.registry());
+
+    ON_CALL(mock_sync_sessions_client_, GetSessionSyncPrefs())
+        .WillByDefault(Return(&session_sync_prefs_));
+    ON_CALL(mock_sync_sessions_client_, GetStoreFactory())
+        .WillByDefault(
+            Return(syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore(
+                store_.get())));
     ON_CALL(mock_sync_sessions_client_, GetLocalDeviceInfo())
         .WillByDefault(Return(&local_device_info_));
     ON_CALL(mock_sync_sessions_client_, GetSyncedWindowDelegatesGetter())
         .WillByDefault(Return(&window_getter_));
     ON_CALL(mock_sync_sessions_client_, GetLocalSessionEventRouter())
         .WillByDefault(Return(window_getter_.router()));
-    ON_CALL(mock_sync_prefs_, GetSyncSessionsGUID())
-        .WillByDefault(Return(kLocalSessionTag));
+
+    session_sync_prefs_.SetSyncSessionsGUID(kLocalSessionTag);
 
     // Even if we use NiceMock, let's be strict about errors and let tests
     // explicitly list them.
@@ -201,10 +202,7 @@
     mock_processor_.DelegateCallsByDefaultTo(real_processor_.get());
     // Instantiate the bridge.
     bridge_ = std::make_unique<SessionSyncBridge>(
-        &mock_sync_sessions_client_, &mock_sync_prefs_,
-        /*store_factory=*/
-        syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore(store_.get()),
-        mock_foreign_sessions_updated_callback_.Get(),
+        &mock_sync_sessions_client_,
         mock_processor_.CreateForwardingProcessor());
   }
 
@@ -305,6 +303,10 @@
 
   void SessionRestoreComplete() { window_getter_.SessionRestoreComplete(); }
 
+  MockSyncSessionsClient& mock_sync_sessions_client() {
+    return mock_sync_sessions_client_;
+  }
+
   SessionSyncBridge* bridge() { return bridge_.get(); }
 
   syncer::MockModelTypeChangeProcessor& mock_processor() {
@@ -315,22 +317,16 @@
     return real_processor_.get();
   }
 
-  base::MockCallback<base::RepeatingClosure>&
-  mock_foreign_sessions_updated_callback() {
-    return mock_foreign_sessions_updated_callback_;
-  }
-
  private:
   base::MessageLoop message_loop_;
   const syncer::DeviceInfo local_device_info_;
   const std::unique_ptr<syncer::ModelTypeStore> store_;
 
   // Dependencies.
+  TestingPrefServiceSimple pref_service_;
+  SessionSyncPrefs session_sync_prefs_;
   testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_;
-  testing::NiceMock<MockSessionSyncPrefs> mock_sync_prefs_;
   testing::NiceMock<MockModelTypeChangeProcessor> mock_processor_;
-  testing::NiceMock<base::MockCallback<base::RepeatingClosure>>
-      mock_foreign_sessions_updated_callback_;
   TestSyncedWindowDelegatesGetter window_getter_;
   FaviconCache favicon_cache_;
 
@@ -464,7 +460,8 @@
   StartSyncing();
 
   ASSERT_THAT(GetAllData(), SizeIs(2));
-  EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()).Times(0);
+  EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated())
+      .Times(0);
 
   // Expectations for the processor.
   std::string header_storage_key;
@@ -998,8 +995,7 @@
   EXPECT_CALL(
       mock_processor(),
       Put(_, EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _)), _));
-  EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run());
-
+  EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated());
   StartSyncing({foreign_header, foreign_tab});
 
   std::vector<const SyncedSession*> foreign_sessions;
@@ -1146,7 +1142,7 @@
   sync_pb::ModelTypeState state;
   state.set_initial_sync_done(true);
 
-  EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run());
+  EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated());
   real_processor()->OnUpdateReceived(
       state, {CreateTombstone(SessionStore::GetClientTag(foreign_header))});
 
@@ -1315,7 +1311,7 @@
   // Mimic the user requesting a session deletion from the UI.
   EXPECT_CALL(mock_processor(), Delete(foreign_header_storage_key, _));
   EXPECT_CALL(mock_processor(), Delete(foreign_tab_storage_key, _));
-  EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run());
+  EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated());
   bridge()->GetOpenTabsUIDelegate()->DeleteForeignSession(kForeignSessionTag);
 
   // Verify what gets exposed to the UI.
@@ -1337,7 +1333,8 @@
   InitializeBridge();
   StartSyncing();
 
-  EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()).Times(0);
+  EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated())
+      .Times(0);
   EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0);
 
   bridge()->GetOpenTabsUIDelegate()->DeleteForeignSession(kLocalSessionTag);
@@ -1355,7 +1352,8 @@
   InitializeBridge();
   StartSyncing();
 
-  EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()).Times(0);
+  EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated())
+      .Times(0);
 
   // Mimic receiving an empty list of remote updates.
   sync_pb::ModelTypeState state;
@@ -1406,7 +1404,7 @@
   EXPECT_CALL(
       mock_processor(),
       Delete(SessionStore::GetTabStorageKey(kStaleSessionTag, kTabNodeId), _));
-  EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run());
+  EXPECT_CALL(mock_sync_sessions_client(), NotifyForeignSessionUpdated());
 
   bridge()->ScheduleGarbageCollection();
   base::RunLoop().RunUntilIdle();
diff --git a/components/sync_sessions/session_sync_prefs.cc b/components/sync_sessions/session_sync_prefs.cc
new file mode 100644
index 0000000..8cb5f266
--- /dev/null
+++ b/components/sync_sessions/session_sync_prefs.cc
@@ -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.
+
+#include "components/sync_sessions/session_sync_prefs.h"
+
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+
+namespace sync_sessions {
+namespace {
+
+// The GUID session sync will use to identify this client, even across sync
+// disable/enable events.
+const char kSyncSessionsGUID[] = "sync.session_sync_guid";
+
+}  // namespace
+
+// static
+void SessionSyncPrefs::RegisterProfilePrefs(PrefRegistrySimple* registry) {
+  registry->RegisterStringPref(kSyncSessionsGUID, std::string());
+}
+
+SessionSyncPrefs::SessionSyncPrefs(PrefService* pref_service)
+    : pref_service_(pref_service) {
+  DCHECK(pref_service);
+}
+
+SessionSyncPrefs::~SessionSyncPrefs() {}
+
+std::string SessionSyncPrefs::GetSyncSessionsGUID() const {
+  return pref_service_->GetString(kSyncSessionsGUID);
+}
+
+void SessionSyncPrefs::SetSyncSessionsGUID(const std::string& guid) {
+  pref_service_->SetString(kSyncSessionsGUID, guid);
+}
+
+}  // namespace sync_sessions
diff --git a/components/sync_sessions/session_sync_prefs.h b/components/sync_sessions/session_sync_prefs.h
new file mode 100644
index 0000000..5e5774a
--- /dev/null
+++ b/components/sync_sessions/session_sync_prefs.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 COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_PREFS_H_
+#define COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_PREFS_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+class PrefService;
+class PrefRegistrySimple;
+
+namespace sync_sessions {
+
+// Use this for the unique machine tag used for session sync.
+class SessionSyncPrefs {
+ public:
+  static void RegisterProfilePrefs(PrefRegistrySimple* registry);
+
+  explicit SessionSyncPrefs(PrefService* pref_service);
+  ~SessionSyncPrefs();
+
+  std::string GetSyncSessionsGUID() const;
+  void SetSyncSessionsGUID(const std::string& guid);
+
+ private:
+  PrefService* const pref_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(SessionSyncPrefs);
+};
+
+}  // namespace sync_sessions
+
+#endif  // COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_PREFS_H_
diff --git a/components/sync_sessions/session_sync_service.cc b/components/sync_sessions/session_sync_service.cc
new file mode 100644
index 0000000..ae81516
--- /dev/null
+++ b/components/sync_sessions/session_sync_service.cc
@@ -0,0 +1,73 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync_sessions/session_sync_service.h"
+
+#include <utility>
+
+#include "base/bind_helpers.h"
+#include "components/sync/base/report_unrecoverable_error.h"
+#include "components/sync/driver/sync_driver_switches.h"
+#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
+#include "components/sync_sessions/favicon_cache.h"
+#include "components/sync_sessions/session_data_type_controller.h"
+#include "components/sync_sessions/session_sync_bridge.h"
+#include "components/sync_sessions/session_sync_prefs.h"
+#include "components/sync_sessions/sessions_sync_manager.h"
+#include "components/sync_sessions/sync_sessions_client.h"
+
+namespace sync_sessions {
+
+SessionSyncService::SessionSyncService(
+    version_info::Channel channel,
+    std::unique_ptr<SyncSessionsClient> sessions_client)
+    : sessions_client_(std::move(sessions_client)) {
+  DCHECK(sessions_client_);
+  if (base::FeatureList::IsEnabled(switches::kSyncUSSSessions)) {
+    sessions_sync_manager_ = std::make_unique<sync_sessions::SessionSyncBridge>(
+        sessions_client_.get(),
+        std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
+            syncer::SESSIONS,
+            base::BindRepeating(&syncer::ReportUnrecoverableError, channel)));
+  } else {
+    sessions_sync_manager_ =
+        std::make_unique<sync_sessions::SessionsSyncManager>(
+            sessions_client_.get());
+  }
+}
+
+SessionSyncService::~SessionSyncService() {}
+
+syncer::GlobalIdMapper* SessionSyncService::GetGlobalIdMapper() const {
+  return sessions_sync_manager_->GetGlobalIdMapper();
+}
+
+OpenTabsUIDelegate* SessionSyncService::GetRawOpenTabsUIDelegate() {
+  return sessions_sync_manager_->GetOpenTabsUIDelegate();
+}
+
+void SessionSyncService::ScheduleGarbageCollection() {
+  sessions_sync_manager_->ScheduleGarbageCollection();
+}
+
+syncer::SyncableService* SessionSyncService::GetSyncableService() {
+  return sessions_sync_manager_->GetSyncableService();
+}
+
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+SessionSyncService::GetControllerDelegate() {
+  return sessions_sync_manager_->GetModelTypeSyncBridge()
+      ->change_processor()
+      ->GetControllerDelegate();
+}
+
+FaviconCache* SessionSyncService::GetFaviconCache() {
+  return sessions_sync_manager_->GetFaviconCache();
+}
+
+void SessionSyncService::SetSyncSessionsGUID(const std::string& guid) {
+  sessions_client_->GetSessionSyncPrefs()->SetSyncSessionsGUID(guid);
+}
+
+}  // namespace sync_sessions
diff --git a/components/sync_sessions/session_sync_service.h b/components/sync_sessions/session_sync_service.h
new file mode 100644
index 0000000..c6bd77d
--- /dev/null
+++ b/components/sync_sessions/session_sync_service.h
@@ -0,0 +1,73 @@
+// 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_SYNC_SESSIONS_SESSION_SYNC_SERVICE_H_
+#define COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_SERVICE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/memory/weak_ptr.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/sync/model/model_type_store.h"
+#include "components/version_info/channel.h"
+
+namespace syncer {
+class GlobalIdMapper;
+class ModelTypeControllerDelegate;
+class SyncableService;
+}  // namespace syncer
+
+namespace sync_sessions {
+
+class AbstractSessionsSyncManager;
+class FaviconCache;
+class OpenTabsUIDelegate;
+class SyncSessionsClient;
+
+// KeyedService responsible session sync (aka tab sync), including favicon sync.
+// This powers things like the history UI, where "Tabs from other devices"
+// exists, as well as the uploading counterpart for other devices to see our
+// local tabs.
+class SessionSyncService : public KeyedService {
+ public:
+  SessionSyncService(version_info::Channel channel,
+                     std::unique_ptr<SyncSessionsClient> sessions_client);
+  ~SessionSyncService() override;
+
+  syncer::GlobalIdMapper* GetGlobalIdMapper() const;
+
+  // Intended for ProfileSyncService: returns the OpenTabsUIDelegate instance,
+  // which is guaranteed to be non-null (independently of whether sync is
+  // running or not)
+  OpenTabsUIDelegate* GetRawOpenTabsUIDelegate();
+
+  // Schedules garbage collection of foreign sessions.
+  void ScheduleGarbageCollection();
+
+  // For ProfileSyncService to initialize the controller for SESSIONS. Exactly
+  // one of the two below will return non-null (depending on a feature toggle).
+  syncer::SyncableService* GetSyncableService();
+  base::WeakPtr<syncer::ModelTypeControllerDelegate> GetControllerDelegate();
+
+  // For ProfileSyncService to initialize the controller for FAVICON_IMAGES and
+  // FAVICON_TRACKING.
+  FaviconCache* GetFaviconCache();
+
+  // Used on Android only, to override the machine tag.
+  void SetSyncSessionsGUID(const std::string& guid);
+
+ private:
+  std::unique_ptr<SyncSessionsClient> sessions_client_;
+
+  // Locally owned SyncableService or ModelTypeSyncBridge implementations.
+  std::unique_ptr<sync_sessions::AbstractSessionsSyncManager>
+      sessions_sync_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(SessionSyncService);
+};
+
+}  // namespace sync_sessions
+
+#endif  // COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_SERVICE_H_
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index a890612..503f362 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -22,6 +22,7 @@
 #include "components/sync/model/sync_merge_result.h"
 #include "components/sync/model/time.h"
 #include "components/sync_sessions/local_session_event_router.h"
+#include "components/sync_sessions/session_sync_prefs.h"
 #include "components/sync_sessions/sync_sessions_client.h"
 #include "components/sync_sessions/tab_node_pool.h"
 
@@ -137,9 +138,7 @@
 // |local_device| is owned by ProfileSyncService, its lifetime exceeds
 // lifetime of SessionSyncManager.
 SessionsSyncManager::SessionsSyncManager(
-    sync_sessions::SyncSessionsClient* sessions_client,
-    syncer::SessionSyncPrefs* sync_prefs,
-    const base::RepeatingClosure& sessions_updated_callback)
+    sync_sessions::SyncSessionsClient* sessions_client)
     : sessions_client_(sessions_client),
       session_tracker_(sessions_client),
       favicon_cache_(sessions_client->GetFaviconService(),
@@ -152,9 +151,7 @@
           base::BindRepeating(&SessionsSyncManager::DeleteForeignSessionFromUI,
                               base::Unretained(this))),
       local_tab_pool_out_of_sync_(true),
-      sync_prefs_(sync_prefs),
-      stale_session_threshold_days_(kDefaultStaleSessionThresholdDays),
-      sessions_updated_callback_(sessions_updated_callback) {}
+      stale_session_threshold_days_(kDefaultStaleSessionThresholdDays) {}
 
 SessionsSyncManager::~SessionsSyncManager() {}
 
@@ -391,8 +388,7 @@
     }
   }
 
-  if (!sessions_updated_callback_.is_null())
-    sessions_updated_callback_.Run();
+  sessions_client_->NotifyForeignSessionUpdated();
   return syncer::SyncError();
 }
 
@@ -502,7 +498,8 @@
     const std::string& cache_guid) {
   DCHECK(current_machine_tag_.empty());
   std::string persisted_guid;
-  persisted_guid = sync_prefs_->GetSyncSessionsGUID();
+  persisted_guid =
+      sessions_client_->GetSessionSyncPrefs()->GetSyncSessionsGUID();
   if (!persisted_guid.empty()) {
     current_machine_tag_ = persisted_guid;
     DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid;
@@ -510,7 +507,8 @@
     DCHECK(!cache_guid.empty());
     current_machine_tag_ = BuildMachineTag(cache_guid);
     DVLOG(1) << "Creating session sync guid: " << current_machine_tag_;
-    sync_prefs_->SetSyncSessionsGUID(current_machine_tag_);
+    sessions_client_->GetSessionSyncPrefs()->SetSyncSessionsGUID(
+        current_machine_tag_);
   }
 }
 
@@ -532,8 +530,8 @@
                            SyncData::CreateLocalDelete(tag, syncer::SESSIONS)));
   }
   AppendDeletionsForTabNodes(tab_node_ids_to_delete, tag, change_output);
-  if (!sessions_updated_callback_.is_null())
-    sessions_updated_callback_.Run();
+
+  sessions_client_->NotifyForeignSessionUpdated();
 }
 
 void SessionsSyncManager::DeleteForeignSessionFromUI(const std::string& tag) {
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
index d632cbb..0805a0d1 100644
--- a/components/sync_sessions/sessions_sync_manager.h
+++ b/components/sync_sessions/sessions_sync_manager.h
@@ -21,7 +21,6 @@
 #include "base/time/time.h"
 #include "components/sessions/core/session_id.h"
 #include "components/sessions/core/session_types.h"
-#include "components/sync/base/sync_prefs.h"
 #include "components/sync/device_info/device_info.h"
 #include "components/sync/model/syncable_service.h"
 #include "components/sync_sessions/abstract_sessions_sync_manager.h"
@@ -54,9 +53,7 @@
                             public syncer::SyncableService,
                             public LocalSessionEventHandlerImpl::Delegate {
  public:
-  SessionsSyncManager(SyncSessionsClient* sessions_client,
-                      syncer::SessionSyncPrefs* sync_prefs,
-                      const base::RepeatingClosure& sessions_updated_callback);
+  explicit SessionsSyncManager(SyncSessionsClient* sessions_client);
   ~SessionsSyncManager() override;
 
   // AbstractSessionsSyncManager implementation.
@@ -188,8 +185,6 @@
   // proves that we are still relevant.
   bool local_tab_pool_out_of_sync_;
 
-  syncer::SessionSyncPrefs* sync_prefs_;
-
   std::unique_ptr<syncer::SyncErrorFactory> error_handler_;
   std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
 
@@ -206,9 +201,6 @@
   std::unique_ptr<sync_sessions::LostNavigationsRecorder>
       lost_navigations_recorder_;
 
-  // Callback to inform interested observer that new sessions data has arrived.
-  base::RepeatingClosure sessions_updated_callback_;
-
   DISALLOW_COPY_AND_ASSIGN(SessionsSyncManager);
 };
 
diff --git a/components/sync_sessions/sessions_sync_manager_unittest.cc b/components/sync_sessions/sessions_sync_manager_unittest.cc
index 46b849b..9f2dc2ba 100644
--- a/components/sync_sessions/sessions_sync_manager_unittest.cc
+++ b/components/sync_sessions/sessions_sync_manager_unittest.cc
@@ -9,10 +9,10 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
-#include "components/sync/driver/fake_sync_client.h"
-#include "components/sync/driver/sync_api_component_factory.h"
+#include "components/prefs/testing_pref_service.h"
 #include "components/sync/model/sync_error_factory_mock.h"
 #include "components/sync_sessions/mock_sync_sessions_client.h"
+#include "components/sync_sessions/session_sync_prefs.h"
 #include "components/sync_sessions/session_sync_test_helper.h"
 #include "components/sync_sessions/sync_sessions_client.h"
 #include "components/sync_sessions/test_synced_window_delegates_getter.h"
@@ -113,21 +113,6 @@
   return testing::AssertionSuccess();
 }
 
-class SessionNotificationObserver {
- public:
-  SessionNotificationObserver() : notified_of_update_(false) {}
-  void NotifyOfUpdate() { notified_of_update_ = true; }
-
-  bool notified_of_update() const { return notified_of_update_; }
-
-  void Reset() {
-    notified_of_update_ = false;
-  }
-
- private:
-  bool notified_of_update_;
-};
-
 class TestSyncChangeProcessor : public syncer::SyncChangeProcessor {
  public:
   explicit TestSyncChangeProcessor(SyncChangeList* output) : output_(output) {}
@@ -188,9 +173,14 @@
                            "Chromium 10k",
                            "Chrome 10k",
                            sync_pb::SyncEnums_DeviceType_TYPE_LINUX,
-                           "device_id") {}
+                           "device_id"),
+        session_sync_prefs_(&pref_service_) {}
 
   void SetUp() override {
+    SessionSyncPrefs::RegisterProfilePrefs(pref_service_.registry());
+
+    ON_CALL(mock_sync_sessions_client_, GetSessionSyncPrefs())
+        .WillByDefault(testing::Return(&session_sync_prefs_));
     ON_CALL(mock_sync_sessions_client_, GetLocalDeviceInfo())
         .WillByDefault(testing::Return(&local_device_info_));
     ON_CALL(mock_sync_sessions_client_, GetSyncedWindowDelegatesGetter())
@@ -198,19 +188,13 @@
     ON_CALL(mock_sync_sessions_client_, GetLocalSessionEventRouter())
         .WillByDefault(testing::Return(window_getter_.router()));
 
-    sync_client_ = std::make_unique<syncer::FakeSyncClient>();
-    sync_prefs_ =
-        std::make_unique<syncer::SyncPrefs>(sync_client_->GetPrefService());
-    manager_ = std::make_unique<SessionsSyncManager>(
-        &mock_sync_sessions_client_, sync_prefs_.get(),
-        base::Bind(&SessionNotificationObserver::NotifyOfUpdate,
-                   base::Unretained(&observer_)));
+    manager_ =
+        std::make_unique<SessionsSyncManager>(&mock_sync_sessions_client_);
   }
 
   void TearDown() override {
     test_processor_ = nullptr;
     helper()->Reset();
-    sync_prefs_.reset();
     manager_.reset();
   }
 
@@ -218,8 +202,6 @@
 
   SessionsSyncManager* manager() { return manager_.get(); }
   SessionSyncTestHelper* helper() { return &helper_; }
-  SessionNotificationObserver* observer() { return &observer_; }
-  syncer::SyncPrefs* sync_prefs() { return sync_prefs_.get(); }
   MockSyncSessionsClient* mock_sync_sessions_client() {
     return &mock_sync_sessions_client_;
   }
@@ -388,10 +370,9 @@
 
  private:
   const syncer::DeviceInfo local_device_info_;
-  std::unique_ptr<syncer::FakeSyncClient> sync_client_;
+  TestingPrefServiceSimple pref_service_;
+  SessionSyncPrefs session_sync_prefs_;
   testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_;
-  std::unique_ptr<syncer::SyncPrefs> sync_prefs_;
-  SessionNotificationObserver observer_;
   std::unique_ptr<SessionsSyncManager> manager_;
   SessionSyncTestHelper helper_;
   TestSyncChangeProcessor* test_processor_ = nullptr;
@@ -1549,7 +1530,6 @@
 // Test that NOTIFICATION_FOREIGN_SESSION_UPDATED is sent when processing
 // sync changes.
 TEST_F(SessionsSyncManagerTest, NotifiedOfUpdates) {
-  ASSERT_FALSE(observer()->notified_of_update());
   InitWithNoSyncData();
 
   std::vector<sync_pb::SessionSpecifics> tabs1;
@@ -1558,20 +1538,18 @@
 
   SyncChangeList changes;
   changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
+  EXPECT_CALL(*mock_sync_sessions_client(), NotifyForeignSessionUpdated());
   manager()->ProcessSyncChanges(FROM_HERE, changes);
-  EXPECT_TRUE(observer()->notified_of_update());
 
   changes.clear();
-  observer()->Reset();
   AddTabsToChangeList(tabs1, SyncChange::ACTION_ADD, &changes);
+  EXPECT_CALL(*mock_sync_sessions_client(), NotifyForeignSessionUpdated());
   manager()->ProcessSyncChanges(FROM_HERE, changes);
-  EXPECT_TRUE(observer()->notified_of_update());
 
   changes.clear();
-  observer()->Reset();
   changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_DELETE));
+  EXPECT_CALL(*mock_sync_sessions_client(), NotifyForeignSessionUpdated());
   manager()->ProcessSyncChanges(FROM_HERE, changes);
-  EXPECT_TRUE(observer()->notified_of_update());
 }
 
 // Test that NOTIFICATION_FOREIGN_SESSION_UPDATED is sent when handling
@@ -1587,10 +1565,8 @@
   changes.push_back(MakeRemoteChange(meta, SyncChange::ACTION_ADD));
   manager()->ProcessSyncChanges(FROM_HERE, changes);
 
-  observer()->Reset();
-  ASSERT_FALSE(observer()->notified_of_update());
+  EXPECT_CALL(*mock_sync_sessions_client(), NotifyForeignSessionUpdated());
   manager()->GetOpenTabsUIDelegate()->DeleteForeignSession(tag);
-  ASSERT_TRUE(observer()->notified_of_update());
 }
 
 // Tests receipt of duplicate tab IDs in the same window.  This should never
diff --git a/components/sync_sessions/sync_sessions_client.h b/components/sync_sessions/sync_sessions_client.h
index a256193f..4459f48 100644
--- a/components/sync_sessions/sync_sessions_client.h
+++ b/components/sync_sessions/sync_sessions_client.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "components/sync/model/model_type_store.h"
 
 class GURL;
 
@@ -21,11 +22,12 @@
 
 namespace syncer {
 class DeviceInfo;
-}
+}  // namespace syncer
 
 namespace sync_sessions {
 
 class LocalSessionEventRouter;
+class SessionSyncPrefs;
 class SyncedWindowDelegatesGetter;
 
 // Interface for clients of a sync sessions datatype. Should be used as a getter
@@ -38,6 +40,8 @@
   // Getters for services that sessions depends on.
   virtual favicon::FaviconService* GetFaviconService() = 0;
   virtual history::HistoryService* GetHistoryService() = 0;
+  virtual SessionSyncPrefs* GetSessionSyncPrefs() = 0;
+  virtual syncer::RepeatingModelTypeStoreFactory GetStoreFactory() = 0;
 
   // Checks if the given url is considered interesting enough to sync. Most urls
   // are considered interesting. Examples of ones that are not are invalid urls,
@@ -57,8 +61,8 @@
   // embedder's context.
   virtual LocalSessionEventRouter* GetLocalSessionEventRouter() = 0;
 
-  // TODO(zea): add getters for the history and favicon services for the favicon
-  // cache to consume once it's componentized.
+  // Called when foreign sessions have been updated.
+  virtual void NotifyForeignSessionUpdated() = 0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SyncSessionsClient);
diff --git a/components/test/data/autofill_assistant/autofill_assistant_target_website.html b/components/test/data/autofill_assistant/autofill_assistant_target_website.html
index 836951c..7c96e97 100644
--- a/components/test/data/autofill_assistant/autofill_assistant_target_website.html
+++ b/components/test/data/autofill_assistant/autofill_assistant_target_website.html
@@ -32,7 +32,7 @@
     section.
     -->
     <div id="full_height_section">
-      <p>Blank Section
+      <p>Blank Section</p>
     </div>
 
     <div>
@@ -49,6 +49,10 @@
       </select>
     </div>
 
+    <div>
+      <input id="input" type="field" value="helloworld" />
+    </div>
+
     <iframe id="iframe" name="test_iframe" width="100%" height="500" src=
         "autofill_assistant_target_website_iframe_one.html"></iframe>
   </body>
diff --git a/components/viz/common/quads/compositor_frame_metadata.h b/components/viz/common/quads/compositor_frame_metadata.h
index 1baee74d..91be80e 100644
--- a/components/viz/common/quads/compositor_frame_metadata.h
+++ b/components/viz/common/quads/compositor_frame_metadata.h
@@ -132,16 +132,16 @@
   // determine if scrolling/scaling in a particular direction is possible.
   float min_page_scale_factor = 0.f;
 
+  // Used to position the location top bar and page content, whose precise
+  // position is computed by the renderer compositor.
+  float top_controls_height = 0.f;
+  float top_controls_shown_ratio = 0.f;
+
 #if defined(OS_ANDROID)
   float max_page_scale_factor = 0.f;
   gfx::SizeF root_layer_size;
   bool root_overflow_y_hidden = false;
 
-  // Used to position the Android location top bar and page content, whose
-  // precise position is computed by the renderer compositor.
-  float top_controls_height = 0.f;
-  float top_controls_shown_ratio = 0.f;
-
   // Used to position Android bottom bar, whose position is computed by the
   // renderer compositor.
   float bottom_controls_height = 0.f;
diff --git a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index 33034de..088058c 100644
--- a/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -499,12 +499,10 @@
                       frame_metadata.root_scroll_offset.x());
   metadata->SetDouble(VideoFrameMetadata::ROOT_SCROLL_OFFSET_Y,
                       frame_metadata.root_scroll_offset.y());
-#if defined(OS_ANDROID)
   metadata->SetDouble(VideoFrameMetadata::TOP_CONTROLS_HEIGHT,
                       frame_metadata.top_controls_height);
   metadata->SetDouble(VideoFrameMetadata::TOP_CONTROLS_SHOWN_RATIO,
                       frame_metadata.top_controls_shown_ratio);
-#endif  // defined(OS_ANDROID)
 
   oracle_.RecordCapture(utilization);
   const int64_t frame_number = next_capture_frame_number_++;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index dcc7cb4..e56eb6e 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1278,6 +1278,8 @@
     "renderer_host/clipboard_host_impl.cc",
     "renderer_host/clipboard_host_impl.h",
     "renderer_host/clipboard_host_impl_mac.mm",
+    "renderer_host/code_cache_host_impl.cc",
+    "renderer_host/code_cache_host_impl.h",
     "renderer_host/cursor_manager.cc",
     "renderer_host/cursor_manager.h",
     "renderer_host/dip_util.cc",
diff --git a/content/browser/accessibility/accessibility_event_recorder_win.cc b/content/browser/accessibility/accessibility_event_recorder_win.cc
index be122ba..0f1c7120 100644
--- a/content/browser/accessibility/accessibility_event_recorder_win.cc
+++ b/content/browser/accessibility/accessibility_event_recorder_win.cc
@@ -210,8 +210,33 @@
     return;
   }
 
+  std::string event_str = AccessibilityEventToStringUTF8(event);
+  if (event_str.empty()) {
+    VLOG(1) << "Ignoring event " << event;
+    return;
+  }
+
+  base::win::ScopedVariant childid_self(CHILDID_SELF);
+  base::win::ScopedVariant role;
+  iaccessible->get_accRole(childid_self, role.Receive());
+  base::win::ScopedVariant state;
+  iaccessible->get_accState(childid_self, state.Receive());
+  int ia_state = V_I4(state.ptr());
+  std::string hwnd_class_name = base::UTF16ToUTF8(gfx::GetClassName(hwnd));
+
+  // Caret is special:
+  // Log all caret events  that occur, with their window class, so that we can
+  // test to make sure they are only occurring on the desired window class.
+  if (ROLE_SYSTEM_CARET == V_I4(role.ptr())) {
+    base::string16 state_str = IAccessibleStateToString(ia_state);
+    std::string log = base::StringPrintf(
+        "%s role=ROLE_SYSTEM_CARET %ls window_class=%s", event_str.c_str(),
+        state_str.c_str(), hwnd_class_name.c_str());
+    OnEvent(log);
+    return;
+  }
+
   if (only_web_events_) {
-    std::string hwnd_class_name = base::UTF16ToUTF8(gfx::GetClassName(hwnd));
     if (hwnd_class_name != "Chrome_RenderWidgetHostHWND")
       return;
 
@@ -227,22 +252,10 @@
       return;
   }
 
-  std::string event_str = AccessibilityEventToStringUTF8(event);
-  if (event_str.empty()) {
-    VLOG(1) << "Ignoring event " << event;
-    return;
-  }
-
-  base::win::ScopedVariant childid_self(CHILDID_SELF);
-  base::win::ScopedVariant role;
-  iaccessible->get_accRole(childid_self, role.Receive());
   base::win::ScopedBstr name_bstr;
   iaccessible->get_accName(childid_self, name_bstr.Receive());
   base::win::ScopedBstr value_bstr;
   iaccessible->get_accValue(childid_self, value_bstr.Receive());
-  base::win::ScopedVariant state;
-  iaccessible->get_accState(childid_self, state.Receive());
-  int ia_state = V_I4(state.ptr());
 
   // Avoid flakiness. Events fired on a WINDOW are out of the control
   // of a test.
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
index 76f0cce..77b9831 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -142,7 +142,8 @@
 void DumpAccessibilityTestBase::ParseHtmlForExtraDirectives(
     const std::string& test_html,
     std::vector<Filter>* filters,
-    std::vector<std::string>* wait_for) {
+    std::vector<std::string>* wait_for,
+    std::vector<std::string>* run_until) {
   for (const std::string& line :
        base::SplitString(test_html, "\n", base::TRIM_WHITESPACE,
                          base::SPLIT_WANT_ALL)) {
@@ -150,6 +151,7 @@
     const std::string& allow_str = formatter_->GetAllowString();
     const std::string& deny_str = formatter_->GetDenyString();
     const std::string& wait_str = "@WAIT-FOR:";
+    const std::string& until_str = "@RUN-UNTIL-EVENT:";
     if (base::StartsWith(line, allow_empty_str,
                          base::CompareCase::SENSITIVE)) {
       filters->push_back(
@@ -168,6 +170,9 @@
     } else if (base::StartsWith(line, wait_str,
                                 base::CompareCase::SENSITIVE)) {
       wait_for->push_back(line.substr(wait_str.size()));
+    } else if (base::StartsWith(line, until_str,
+                                base::CompareCase::SENSITIVE)) {
+      run_until->push_back(line.substr(until_str.size()));
     }
   }
 }
@@ -254,9 +259,10 @@
 
   // Parse filters and other directives in the test file.
   std::vector<std::string> wait_for;
+  std::vector<std::string> run_until;
   filters_.clear();
   AddDefaultFilters(&filters_);
-  ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for);
+  ParseHtmlForExtraDirectives(html_contents, &filters_, &wait_for, &run_until);
 
   // Get the test URL.
   GURL url(embedded_test_server()->GetURL(
@@ -354,7 +360,7 @@
   }
 
   // Call the subclass to dump the output.
-  std::vector<std::string> actual_lines = Dump();
+  std::vector<std::string> actual_lines = Dump(run_until);
   std::string actual_contents_for_output =
       base::JoinString(actual_lines, "\n") + "\n";
 
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.h b/content/browser/accessibility/dump_accessibility_browsertest_base.h
index 0dfb953b..35a8e57 100644
--- a/content/browser/accessibility/dump_accessibility_browsertest_base.h
+++ b/content/browser/accessibility/dump_accessibility_browsertest_base.h
@@ -47,7 +47,8 @@
   // including the load complete accessibility event. The subclass should
   // dump whatever that specific test wants to dump, returning the result
   // as a sequence of strings.
-  virtual std::vector<std::string> Dump() = 0;
+  virtual std::vector<std::string> Dump(
+      std::vector<std::string>& run_until) = 0;
 
   // Add the default filters that are applied to all tests.
   virtual void AddDefaultFilters(
@@ -92,7 +93,8 @@
   void ParseHtmlForExtraDirectives(
       const std::string& test_html,
       std::vector<AccessibilityTreeFormatter::Filter>* filters,
-      std::vector<std::string>* wait_for);
+      std::vector<std::string>* wait_for,
+      std::vector<std::string>* run_until);
 
   // Create the right AccessibilityTreeFormatter subclass.
   AccessibilityTreeFormatter* CreateAccessibilityTreeFormatter();
diff --git a/content/browser/accessibility/dump_accessibility_events_browsertest.cc b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
index 28df2b6b4..3a5dd45c 100644
--- a/content/browser/accessibility/dump_accessibility_events_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_events_browsertest.cc
@@ -69,7 +69,7 @@
         base::ASCIIToUTF16("EVENT_OBJECT_FOCUS*DOCUMENT*"), Filter::DENY));
   }
 
-  std::vector<std::string> Dump() override;
+  std::vector<std::string> Dump(std::vector<std::string>& run_until) override;
 
   void OnDiffFailed() override;
   void RunEventTest(const base::FilePath::CharType* file_path);
@@ -79,7 +79,24 @@
   base::string16 final_tree_;
 };
 
-std::vector<std::string> DumpAccessibilityEventsTest::Dump() {
+bool IsRecordingComplete(AccessibilityEventRecorder& event_recorder,
+                         std::vector<std::string>& run_until) {
+  // If no @RUN-UNTIL-EVENT directives, then having any events is enough.
+  if (run_until.empty())
+    return true;
+
+  std::vector<std::string> event_logs = event_recorder.event_logs();
+
+  for (size_t i = 0; i < event_logs.size(); ++i)
+    for (size_t j = 0; j < run_until.size(); ++j)
+      if (event_logs[i].find(run_until[j]) != std::string::npos)
+        return true;
+
+  return false;
+}
+
+std::vector<std::string> DumpAccessibilityEventsTest::Dump(
+    std::vector<std::string>& run_until) {
   WebContentsImpl* web_contents = static_cast<WebContentsImpl*>(
       shell()->web_contents());
   base::ProcessId pid = base::GetCurrentProcId();
@@ -103,9 +120,11 @@
   web_contents->GetMainFrame()->ExecuteJavaScriptForTests(
       base::ASCIIToUTF16("go()"));
 
-  // Wait for at least one accessibility event generated in response to
-  // that function.
-  waiter->WaitForNotification();
+  for (;;) {
+    waiter->WaitForNotification();  // Run at least once.
+    if (IsRecordingComplete(*event_recorder, run_until))
+      break;
+  }
 
   // More than one accessibility event could have been generated.
   // To make sure we've received all accessibility events, add a
@@ -269,6 +288,12 @@
   RunEventTest(FILE_PATH_LITERAL("checked-state-changed.html"));
 }
 
+// http:/crbug.com/889013
+IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
+                       DISABLED_AccessibilityEventsCaretMove) {
+  RunEventTest(FILE_PATH_LITERAL("caret-move.html"));
+}
+
 IN_PROC_BROWSER_TEST_F(DumpAccessibilityEventsTest,
                        AccessibilityEventsCSSDisplay) {
   RunEventTest(FILE_PATH_LITERAL("css-display.html"));
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 5436917..2117370 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -125,7 +125,7 @@
     RunTest(test_file, "accessibility/regression");
   }
 
-  std::vector<std::string> Dump() override {
+  std::vector<std::string> Dump(std::vector<std::string>& unused) override {
     std::unique_ptr<AccessibilityTreeFormatter> formatter(
         CreateAccessibilityTreeFormatter());
     formatter->SetFilters(filters_);
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 04705fb..8f4f480 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -175,16 +175,11 @@
       media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_X, &root_scroll_offset_x);
   success &= frame.metadata()->GetDouble(
       media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_Y, &root_scroll_offset_y);
-#if defined(OS_ANDROID)
   success &= frame.metadata()->GetDouble(
       media::VideoFrameMetadata::TOP_CONTROLS_HEIGHT, top_controls_height);
   success &= frame.metadata()->GetDouble(
       media::VideoFrameMetadata::TOP_CONTROLS_SHOWN_RATIO,
       top_controls_shown_ratio);
-#else
-  *top_controls_height = 0.;
-  *top_controls_shown_ratio = 0.;
-#endif  // defined(OS_ANDROID)
   DCHECK(success);
 
   root_scroll_offset->set_x(root_scroll_offset_x);
@@ -948,13 +943,11 @@
   if (snapshot_size.IsEmpty())
     return;
 
-  double top_controls_height = 0.;
-  double top_controls_shown_ratio = 0.;
-#if defined(OS_ANDROID)
-  top_controls_height = last_compositor_frame_metadata_.top_controls_height;
-  top_controls_shown_ratio =
+  double top_controls_height =
+      last_compositor_frame_metadata_.top_controls_height;
+  double top_controls_shown_ratio =
       last_compositor_frame_metadata_.top_controls_shown_ratio;
-#endif
+
   std::unique_ptr<Page::ScreencastFrameMetadata> page_metadata =
       BuildScreencastFrameMetadata(
           surface_size, last_compositor_frame_metadata_.device_scale_factor,
diff --git a/content/browser/fileapi/file_system_manager_impl.cc b/content/browser/fileapi/file_system_manager_impl.cc
index 9a9d1839..29f1d2d 100644
--- a/content/browser/fileapi/file_system_manager_impl.cc
+++ b/content/browser/fileapi/file_system_manager_impl.cc
@@ -123,9 +123,11 @@
 
 FileSystemManagerImpl::FileSystemManagerImpl(
     int process_id,
+    int frame_id,
     storage::FileSystemContext* file_system_context,
     scoped_refptr<ChromeBlobStorageContext> blob_storage_context)
     : process_id_(process_id),
+      frame_id_(frame_id),
       context_(file_system_context),
       security_policy_(ChildProcessSecurityPolicyImpl::GetInstance()),
       blob_storage_context_(blob_storage_context),
@@ -590,8 +592,7 @@
   std::move(callback).Run(base::File::FILE_OK, std::move(writer));
 }
 
-void FileSystemManagerImpl::ChooseEntry(int32_t render_frame_id,
-                                        ChooseEntryCallback callback) {
+void FileSystemManagerImpl::ChooseEntry(ChooseEntryCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (!base::FeatureList::IsEnabled(blink::features::kWritableFilesAPI)) {
     bindings_.ReportBadMessage("FSMI_WRITABLE_FILES_DISABLED");
@@ -601,7 +602,7 @@
   base::PostTaskWithTraits(
       FROM_HERE, {BrowserThread::UI},
       base::BindOnce(
-          &FileSystemChooser::CreateAndShow, process_id_, render_frame_id,
+          &FileSystemChooser::CreateAndShow, process_id_, frame_id_,
           std::move(callback),
           base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO})));
 }
diff --git a/content/browser/fileapi/file_system_manager_impl.h b/content/browser/fileapi/file_system_manager_impl.h
index f5e4cbf..e92c5e46 100644
--- a/content/browser/fileapi/file_system_manager_impl.h
+++ b/content/browser/fileapi/file_system_manager_impl.h
@@ -57,9 +57,12 @@
 class CONTENT_EXPORT FileSystemManagerImpl
     : public blink::mojom::FileSystemManager {
  public:
-  // Used by the renderer process host on the UI thread.
+  // Constructed and held by the render frame host and render process host on
+  // the UI thread. Used by render frames (via the render frame host), workers
+  // and pepper (via the render process host).
   FileSystemManagerImpl(
       int process_id,
+      int frame_id,
       storage::FileSystemContext* file_system_context,
       scoped_refptr<ChromeBlobStorageContext> blob_storage_context);
   ~FileSystemManagerImpl() override;
@@ -122,8 +125,7 @@
                        GetPlatformPathCallback callback) override;
   void CreateWriter(const GURL& file_path,
                     CreateWriterCallback callback) override;
-  void ChooseEntry(int32_t render_frame_id,
-                   ChooseEntryCallback callback) override;
+  void ChooseEntry(ChooseEntryCallback callback) override;
 
  private:
   class FileSystemCancellableOperationImpl;
@@ -206,6 +208,7 @@
   void OnConnectionErrorForOpListeners(OperationListenerID listener_id);
 
   const int process_id_;
+  const int frame_id_;
   storage::FileSystemContext* const context_;
   ChildProcessSecurityPolicyImpl* const security_policy_;
   const scoped_refptr<ChromeBlobStorageContext> blob_storage_context_;
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index 5d294f8..f17c20d 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -92,7 +92,7 @@
   void TakeFocus(bool reverse) override;
   int GetTopControlsHeight() const override;
   int GetBottomControlsHeight() const override;
-  bool DoBrowserControlsShrinkBlinkSize() const override;
+  bool DoBrowserControlsShrinkRendererSize() const override;
   virtual void OnFindReply(int request_id,
                            int number_of_matches,
                            const gfx::Rect& selection_rect,
@@ -1025,14 +1025,14 @@
 }
 
 bool InterstitialPageImpl::InterstitialPageRVHDelegateView::
-    DoBrowserControlsShrinkBlinkSize() const {
+    DoBrowserControlsShrinkRendererSize() const {
   if (!interstitial_page_->web_contents())
     return false;
   WebContentsImpl* web_contents =
       static_cast<WebContentsImpl*>(interstitial_page_->web_contents());
   if (!web_contents || !web_contents->GetDelegateView())
     return false;
-  return web_contents->GetDelegateView()->DoBrowserControlsShrinkBlinkSize();
+  return web_contents->GetDelegateView()->DoBrowserControlsShrinkRendererSize();
 }
 
 void InterstitialPageImpl::InterstitialPageRVHDelegateView::OnFindReply(
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index a187e2df..93efefee 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -40,6 +40,7 @@
 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/download/mhtml_generation_manager.h"
 #include "content/browser/file_url_loader_factory.h"
+#include "content/browser/fileapi/file_system_manager_impl.h"
 #include "content/browser/fileapi/file_system_url_loader_factory.h"
 #include "content/browser/frame_host/cross_process_frame_connector.h"
 #include "content/browser/frame_host/debug_urls.h"
@@ -3594,6 +3595,15 @@
                           GetProcess()->GetID(), routing_id_),
       base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}));
 
+  file_system_manager_.reset(new FileSystemManagerImpl(
+      GetProcess()->GetID(), routing_id_,
+      GetProcess()->GetStoragePartition()->GetFileSystemContext(),
+      ChromeBlobStorageContext::GetFor(GetProcess()->GetBrowserContext())));
+  registry_->AddInterface(
+      base::BindRepeating(&FileSystemManagerImpl::BindRequest,
+                          base::Unretained(file_system_manager_.get())),
+      base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}));
+
   if (Portal::IsEnabled()) {
     registry_->AddInterface(base::BindRepeating(IgnoreResult(&Portal::Create),
                                                 base::Unretained(this)));
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 894ab5f2..baf6df3 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -1617,6 +1617,10 @@
   // Hosts blink::mojom::PresentationService for the RenderFrame.
   std::unique_ptr<PresentationServiceImpl> presentation_service_;
 
+  // Hosts blink::mojom::FileSystemManager for the RenderFrame.
+  std::unique_ptr<FileSystemManagerImpl, BrowserThread::DeleteOnIOThread>
+      file_system_manager_;
+
 #if !defined(OS_ANDROID)
   std::unique_ptr<AuthenticatorImpl> authenticator_impl_;
 #endif
diff --git a/content/browser/renderer_host/code_cache_host_impl.cc b/content/browser/renderer_host/code_cache_host_impl.cc
new file mode 100644
index 0000000..d9fa155
--- /dev/null
+++ b/content/browser/renderer_host/code_cache_host_impl.cc
@@ -0,0 +1,217 @@
+// 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/renderer_host/code_cache_host_impl.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/task/post_task.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "content/browser/cache_storage/cache_storage_cache.h"
+#include "content/browser/cache_storage/cache_storage_cache_handle.h"
+#include "content/browser/cache_storage/cache_storage_context_impl.h"
+#include "content/browser/cache_storage/cache_storage_manager.h"
+#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/code_cache/generated_code_cache.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/browser/storage_partition_impl.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_features.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/base/io_buffer.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+using blink::mojom::CacheStorageError;
+
+namespace content {
+
+namespace {
+
+void NoOpCacheStorageErrorCallback(CacheStorageCacheHandle cache_handle,
+                                   CacheStorageError error) {}
+
+base::Optional<url::Origin> GetRendererOrigin(const GURL& url,
+                                              int render_process_id) {
+  GURL requesting_url =
+      ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(
+          render_process_id);
+
+  if (!requesting_url.is_valid() || !url.is_valid())
+    return base::nullopt;
+
+  url::Origin origin = url::Origin::Create(requesting_url);
+
+  // Don't cache the code corresponding to unique origins. The same-origin
+  // checks should always fail for unique origins but the serialized value of
+  // unique origins does not ensure this.
+  if (origin.unique())
+    return base::nullopt;
+
+  return origin;
+}
+
+}  // namespace
+
+CodeCacheHostImpl::CodeCacheHostImpl(
+    int render_process_id,
+    scoped_refptr<CacheStorageContextImpl> cache_storage_context,
+    scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context)
+    : render_process_id_(render_process_id),
+      cache_storage_context_(std::move(cache_storage_context)),
+      generated_code_cache_context_(std::move(generated_code_cache_context)),
+      weak_ptr_factory_(this) {}
+
+CodeCacheHostImpl::~CodeCacheHostImpl() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
+
+// static
+void CodeCacheHostImpl::Create(
+    int render_process_id,
+    scoped_refptr<CacheStorageContextImpl> cache_storage_context,
+    scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context,
+    blink::mojom::CodeCacheHostRequest request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  mojo::MakeStrongBinding(
+      std::make_unique<CodeCacheHostImpl>(
+          render_process_id, std::move(cache_storage_context),
+          std::move(generated_code_cache_context)),
+      std::move(request));
+}
+
+void CodeCacheHostImpl::DidGenerateCacheableMetadata(
+    const GURL& url,
+    base::Time expected_response_time,
+    const std::vector<uint8_t>& data) {
+  if (!url.SchemeIsHTTPOrHTTPS()) {
+    mojo::ReportBadMessage("Invalid URL scheme for code cache.");
+    return;
+  }
+
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  if (!base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) {
+    base::PostTaskWithTraits(
+        FROM_HERE, {BrowserThread::UI},
+        base::BindOnce(&CodeCacheHostImpl::DidGenerateCacheableMetadataOnUI,
+                       render_process_id_, url, expected_response_time, data));
+  } else {
+    if (!generated_code_cache_context_ ||
+        !generated_code_cache_context_->generated_code_cache())
+      return;
+
+    base::Optional<url::Origin> requesting_origin =
+        GetRendererOrigin(url, render_process_id_);
+    if (!requesting_origin)
+      return;
+
+    generated_code_cache_context_->generated_code_cache()->WriteData(
+        url, *requesting_origin, expected_response_time, data);
+  }
+}
+
+void CodeCacheHostImpl::FetchCachedCode(const GURL& url,
+                                        FetchCachedCodeCallback callback) {
+  if (!generated_code_cache_context_ ||
+      !generated_code_cache_context_->generated_code_cache()) {
+    std::move(callback).Run(base::Time(), std::vector<uint8_t>());
+    return;
+  }
+
+  base::Optional<url::Origin> requesting_origin =
+      GetRendererOrigin(url, render_process_id_);
+  if (!requesting_origin) {
+    std::move(callback).Run(base::Time(), std::vector<uint8_t>());
+    return;
+  }
+
+  auto read_callback = base::BindRepeating(
+      &CodeCacheHostImpl::OnReceiveCachedCode, weak_ptr_factory_.GetWeakPtr(),
+      base::Passed(&callback));
+  generated_code_cache_context_->generated_code_cache()->FetchEntry(
+      url, *requesting_origin, read_callback);
+}
+
+void CodeCacheHostImpl::ClearCodeCacheEntry(const GURL& url) {
+  if (!generated_code_cache_context_ ||
+      !generated_code_cache_context_->generated_code_cache())
+    return;
+
+  base::Optional<url::Origin> requesting_origin =
+      GetRendererOrigin(url, render_process_id_);
+  if (!requesting_origin)
+    return;
+
+  generated_code_cache_context_->generated_code_cache()->DeleteEntry(
+      url, *requesting_origin);
+}
+
+void CodeCacheHostImpl::DidGenerateCacheableMetadataInCacheStorage(
+    const GURL& url,
+    base::Time expected_response_time,
+    const std::vector<uint8_t>& data,
+    const url::Origin& cache_storage_origin,
+    const std::string& cache_storage_cache_name) {
+  scoped_refptr<net::IOBuffer> buf =
+      base::MakeRefCounted<net::IOBuffer>(data.size());
+  if (!data.empty())
+    memcpy(buf->data(), &data.front(), data.size());
+
+  cache_storage_context_->cache_manager()->OpenCache(
+      cache_storage_origin, CacheStorageOwner::kCacheAPI,
+      cache_storage_cache_name,
+      base::BindOnce(&CodeCacheHostImpl::OnCacheStorageOpenCallback,
+                     weak_ptr_factory_.GetWeakPtr(), url,
+                     expected_response_time, buf, data.size()));
+}
+
+void CodeCacheHostImpl::OnReceiveCachedCode(FetchCachedCodeCallback callback,
+                                            const base::Time& response_time,
+                                            const std::vector<uint8_t>& data) {
+  // TODO(crbug.com/867848): Pass the data as a mojo data pipe instead
+  // of vector<uint8>
+  std::move(callback).Run(response_time, data);
+}
+
+void CodeCacheHostImpl::OnCacheStorageOpenCallback(
+    const GURL& url,
+    base::Time expected_response_time,
+    scoped_refptr<net::IOBuffer> buf,
+    int buf_len,
+    CacheStorageCacheHandle cache_handle,
+    CacheStorageError error) {
+  if (error != CacheStorageError::kSuccess || !cache_handle.value())
+    return;
+  CacheStorageCache* cache = cache_handle.value();
+  cache->WriteSideData(
+      base::BindOnce(&NoOpCacheStorageErrorCallback, std::move(cache_handle)),
+      url, expected_response_time, buf, buf_len);
+}
+
+// static
+void CodeCacheHostImpl::DidGenerateCacheableMetadataOnUI(
+    int render_process_id,
+    const GURL& url,
+    base::Time expected_response_time,
+    const std::vector<uint8_t>& data) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  RenderProcessHost* host = RenderProcessHost::FromID(render_process_id);
+  if (!host)
+    return;
+
+  // Use the same priority for the metadata write as for script
+  // resources (see defaultPriorityForResourceType() in WebKit's
+  // CachedResource.cpp). Note that WebURLRequest::PriorityMedium
+  // corresponds to net::LOW (see ConvertWebKitPriorityToNetPriority()
+  // in weburlloader_impl.cc).
+  const net::RequestPriority kPriority = net::LOW;
+  host->GetStoragePartition()->GetNetworkContext()->WriteCacheMetadata(
+      url, kPriority, expected_response_time, data);
+}
+
+}  // namespace content
diff --git a/content/browser/renderer_host/code_cache_host_impl.h b/content/browser/renderer_host/code_cache_host_impl.h
new file mode 100644
index 0000000..18e9b4ba
--- /dev/null
+++ b/content/browser/renderer_host/code_cache_host_impl.h
@@ -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.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_CODE_CACHE_HOST_IMPL_H_
+#define CONTENT_BROWSER_RENDERER_HOST_CODE_CACHE_HOST_IMPL_H_
+
+#include <string>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+#include "content/common/content_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom.h"
+#include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h"
+
+class GURL;
+
+namespace net {
+class IOBuffer;
+}
+
+namespace url {
+class Origin;
+}
+
+namespace content {
+
+class CacheStorageContextImpl;
+class CacheStorageCacheHandle;
+class GeneratedCodeCacheContext;
+
+// The implementation of a CodeCacheHost, which stores and retrieves resource
+// metadata, either bytecode or native code, generated by a renderer process.
+// Instances of this class are owned by by the Mojo pipe that's passed to the
+// renderer process via StrongBinding.
+// Instances of this class must be created and used on the IO thread.
+class CONTENT_EXPORT CodeCacheHostImpl : public blink::mojom::CodeCacheHost {
+ public:
+  CodeCacheHostImpl(
+      int render_process_id,
+      scoped_refptr<CacheStorageContextImpl> cache_storage_context,
+      scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context);
+  ~CodeCacheHostImpl() override;
+
+  static void Create(
+      int render_process_id,
+      scoped_refptr<CacheStorageContextImpl> cache_storage_context,
+      scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context,
+      blink::mojom::CodeCacheHostRequest request);
+
+ private:
+  // blink::mojom::CodeCacheHost implementation.
+  void DidGenerateCacheableMetadata(const GURL& url,
+                                    base::Time expected_response_time,
+                                    const std::vector<uint8_t>& data) override;
+  void FetchCachedCode(const GURL& url, FetchCachedCodeCallback) override;
+  void ClearCodeCacheEntry(const GURL& url) override;
+  void DidGenerateCacheableMetadataInCacheStorage(
+      const GURL& url,
+      base::Time expected_response_time,
+      const std::vector<uint8_t>& data,
+      const url::Origin& cache_storage_origin,
+      const std::string& cache_storage_cache_name) override;
+
+  // Helpers.
+  void OnReceiveCachedCode(FetchCachedCodeCallback callback,
+                           const base::Time& response_time,
+                           const std::vector<uint8_t>& data);
+  void OnCacheStorageOpenCallback(const GURL& url,
+                                  base::Time expected_response_time,
+                                  scoped_refptr<net::IOBuffer> buf,
+                                  int buf_len,
+                                  CacheStorageCacheHandle cache_handle,
+                                  blink::mojom::CacheStorageError error);
+  static void DidGenerateCacheableMetadataOnUI(
+      int render_process_id,
+      const GURL& url,
+      base::Time expected_response_time,
+      const std::vector<uint8_t>& data);
+
+  // Our render process host ID, used to bind to the correct render process.
+  const int render_process_id_;
+
+  scoped_refptr<CacheStorageContextImpl> cache_storage_context_;
+
+  scoped_refptr<GeneratedCodeCacheContext> generated_code_cache_context_;
+
+  base::WeakPtrFactory<CodeCacheHostImpl> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CodeCacheHostImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_CODE_CACHE_HOST_IMPL_H_
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index c550ca0..b52eed53 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -184,15 +184,16 @@
     // Set up a callback to automatically re-connect if we lose our
     // connection.
     host_frame_sink_manager.SetConnectionLostCallback(base::BindRepeating(
-        []() { CompositorDependencies::Get().OnVizFrameSinkManagerLost(); }));
+        []() { CompositorDependencies::Get().CreateVizFrameSinkManager(); }));
 
-    BrowserMainLoop::GetInstance()
-        ->gpu_channel_establish_factory()
-        ->EstablishGpuChannel(base::BindOnce(
-            &CompositorDependencies::
-                OnReadyToConnectVizFrameSinkManagerOnMainThread,
-            base::Unretained(this), std::move(frame_sink_manager_request),
-            frame_sink_manager_client.PassInterface()));
+    pending_connect_viz_on_main_thread_ = base::BindOnce(
+        &CompositorDependencies::
+            OnReadyToConnectVizFrameSinkManagerOnMainThread,
+        base::Unretained(this), std::move(frame_sink_manager_request),
+        frame_sink_manager_client.PassInterface());
+
+    // Will connect using the above callback if we are foreground.
+    TryEstablishVizConnectionIfNeeded();
   }
 
   SingleThreadTaskGraphRunner task_graph_runner;
@@ -274,18 +275,14 @@
     }
   }
 
-  void OnVizFrameSinkManagerLost() {
-    needs_recreate_viz_frame_sink_manager_ = true;
-    TryRecreateVizFrameSinkManagerIfNeeded();
-  }
-
-  void TryRecreateVizFrameSinkManagerIfNeeded() {
-    // We don't recreate the frame sink manager if backgrounded, as the OS may
+  void TryEstablishVizConnectionIfNeeded() {
+    // We don't connect to the viz process if backgrounded, as the OS may
     // repeatedly kill the resulting process. Instead wait until we come to the
     // foreground.
-    if (needs_recreate_viz_frame_sink_manager_ && application_is_foreground_) {
-      needs_recreate_viz_frame_sink_manager_ = false;
-      CreateVizFrameSinkManager();
+    if (pending_connect_viz_on_main_thread_ && application_is_foreground_) {
+      BrowserMainLoop::GetInstance()
+          ->gpu_channel_establish_factory()
+          ->EstablishGpuChannel(std::move(pending_connect_viz_on_main_thread_));
     }
   }
 
@@ -333,7 +330,7 @@
         SendOnForegroundedToGpuService();
         low_end_background_cleanup_task_.Cancel();
         application_is_foreground_ = true;
-        TryRecreateVizFrameSinkManagerIfNeeded();
+        TryEstablishVizConnectionIfNeeded();
         break;
       case base::android::APPLICATION_STATE_HAS_STOPPED_ACTIVITIES:
       case base::android::APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES:
@@ -351,7 +348,7 @@
   // An instance of Android AppListener.
   std::unique_ptr<base::android::ApplicationStatusListener> app_listener_;
   bool application_is_foreground_ = true;
-  bool needs_recreate_viz_frame_sink_manager_ = false;
+  gpu::GpuChannelEstablishedCallback pending_connect_viz_on_main_thread_;
 };
 
 const unsigned int kMaxDisplaySwapBuffers = 1U;
diff --git a/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc b/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
index d51f881..ffd3651 100644
--- a/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
+++ b/content/browser/renderer_host/media/service_video_capture_device_launcher_unittest.cc
@@ -51,6 +51,10 @@
                                    virtual_device) override {
     NOTIMPLEMENTED();
   }
+  void RegisterVirtualDevicesChangedObserver(
+      video_capture::mojom::DevicesChangedObserverPtr observer) override {
+    NOTIMPLEMENTED();
+  }
 
   MOCK_METHOD1(DoGetDeviceInfos, void(GetDeviceInfosCallback& callback));
   MOCK_METHOD3(DoCreateDevice,
diff --git a/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc b/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
index 0b5aecf..2467c35 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
+++ b/content/browser/renderer_host/media/service_video_capture_provider_unittest.cc
@@ -80,6 +80,10 @@
                                    virtual_device) override {
     NOTIMPLEMENTED();
   }
+  void RegisterVirtualDevicesChangedObserver(
+      video_capture::mojom::DevicesChangedObserverPtr observer) override {
+    NOTIMPLEMENTED();
+  }
 
   MOCK_METHOD1(DoGetDeviceInfos, void(GetDeviceInfosCallback& callback));
   MOCK_METHOD3(DoCreateDevice,
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 0b441d6..96f0ddc 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -25,13 +25,7 @@
 #include "content/browser/bad_message.h"
 #include "content/browser/blob_storage/chrome_blob_storage_context.h"
 #include "content/browser/browser_main_loop.h"
-#include "content/browser/cache_storage/cache_storage_cache.h"
-#include "content/browser/cache_storage/cache_storage_cache_handle.h"
-#include "content/browser/cache_storage/cache_storage_context_impl.h"
-#include "content/browser/cache_storage/cache_storage_manager.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/code_cache/generated_code_cache.h"
-#include "content/browser/code_cache/generated_code_cache_context.h"
 #include "content/browser/gpu/gpu_data_manager_impl.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
@@ -62,7 +56,6 @@
 #include "net/base/io_buffer.h"
 #include "net/base/mime_util.h"
 #include "net/base/request_priority.h"
-#include "net/http/http_cache.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/mojom/network_context.mojom.h"
@@ -85,36 +78,11 @@
 #include "base/threading/platform_thread.h"
 #endif
 
-using blink::mojom::CacheStorageError;
-
 namespace content {
 namespace {
 
 const uint32_t kRenderFilteredMessageClasses[] = {ViewMsgStart};
 
-void NoOpCacheStorageErrorCallback(CacheStorageCacheHandle cache_handle,
-                                   CacheStorageError error) {}
-
-base::Optional<url::Origin> GetRendererOrigin(const GURL& url,
-                                              int render_process_id) {
-  GURL requesting_url =
-      ChildProcessSecurityPolicyImpl::GetInstance()->GetOriginLock(
-          render_process_id);
-
-  if (!requesting_url.is_valid() || !url.is_valid())
-    return base::nullopt;
-
-  url::Origin origin = url::Origin::Create(requesting_url);
-
-  // Don't cache the code corresponding to unique origins. The same-origin
-  // checks should always fail for unique origins but the serialized value of
-  // unique origins does not ensure this.
-  if (origin.unique())
-    return base::nullopt;
-
-  return origin;
-}
-
 }  // namespace
 
 RenderMessageFilter::RenderMessageFilter(
@@ -122,9 +90,7 @@
     BrowserContext* browser_context,
     net::URLRequestContextGetter* request_context,
     RenderWidgetHelper* render_widget_helper,
-    MediaInternals* media_internals,
-    CacheStorageContextImpl* cache_storage_context,
-    GeneratedCodeCacheContext* generated_code_cache_context)
+    MediaInternals* media_internals)
     : BrowserMessageFilter(kRenderFilteredMessageClasses,
                            arraysize(kRenderFilteredMessageClasses)),
       BrowserAssociatedInterface<mojom::RenderMessageFilter>(this, this),
@@ -134,8 +100,6 @@
       render_widget_helper_(render_widget_helper),
       render_process_id_(render_process_id),
       media_internals_(media_internals),
-      cache_storage_context_(cache_storage_context),
-      generated_code_cache_context_(generated_code_cache_context),
       weak_ptr_factory_(this) {
   DCHECK(request_context_.get());
 
@@ -227,118 +191,6 @@
 }
 #endif
 
-void RenderMessageFilter::DidGenerateCacheableMetadata(
-    const GURL& url,
-    base::Time expected_response_time,
-    const std::vector<uint8_t>& data) {
-  if (!url.SchemeIsHTTPOrHTTPS()) {
-    bad_message::ReceivedBadMessage(
-        this, bad_message::RMF_BAD_URL_CACHEABLE_METADATA);
-    return;
-  }
-
-  DCHECK_CURRENTLY_ON(BrowserThread::IO);
-
-  if (!base::FeatureList::IsEnabled(features::kIsolatedCodeCache)) {
-    base::PostTaskWithTraits(
-        FROM_HERE, {BrowserThread::UI},
-        base::BindOnce(&RenderMessageFilter::DidGenerateCacheableMetadataOnUI,
-                       this, url, expected_response_time, data));
-  } else {
-    if (!generated_code_cache_context_ ||
-        !generated_code_cache_context_->generated_code_cache())
-      return;
-
-    base::Optional<url::Origin> requesting_origin =
-        GetRendererOrigin(url, render_process_id_);
-    if (!requesting_origin)
-      return;
-
-    generated_code_cache_context_->generated_code_cache()->WriteData(
-        url, *requesting_origin, expected_response_time, data);
-  }
-}
-
-void RenderMessageFilter::FetchCachedCode(const GURL& url,
-                                          FetchCachedCodeCallback callback) {
-  if (!generated_code_cache_context_ ||
-      !generated_code_cache_context_->generated_code_cache()) {
-    std::move(callback).Run(base::Time(), std::vector<uint8_t>());
-    return;
-  }
-
-  base::Optional<url::Origin> requesting_origin =
-      GetRendererOrigin(url, render_process_id_);
-  if (!requesting_origin) {
-    std::move(callback).Run(base::Time(), std::vector<uint8_t>());
-    return;
-  }
-
-  base::RepeatingCallback<void(const base::Time&, const std::vector<uint8_t>&)>
-      read_callback = base::BindRepeating(
-          &RenderMessageFilter::OnReceiveCachedCode,
-          weak_ptr_factory_.GetWeakPtr(), base::Passed(&callback));
-  generated_code_cache_context_->generated_code_cache()->FetchEntry(
-      url, *requesting_origin, read_callback);
-}
-
-void RenderMessageFilter::OnReceiveCachedCode(
-    FetchCachedCodeCallback callback,
-    const base::Time& response_time,
-    const std::vector<uint8_t>& data) {
-  // TODO(crbug.com/867848): Pass the data as a mojo data pipe instead
-  // of vector<uint8>
-  std::move(callback).Run(response_time, data);
-}
-
-void RenderMessageFilter::ClearCodeCacheEntry(const GURL& url) {
-  if (!generated_code_cache_context_ ||
-      !generated_code_cache_context_->generated_code_cache())
-    return;
-
-  base::Optional<url::Origin> requesting_origin =
-      GetRendererOrigin(url, render_process_id_);
-  if (!requesting_origin)
-    return;
-
-  generated_code_cache_context_->generated_code_cache()->DeleteEntry(
-      url, *requesting_origin);
-}
-
-void RenderMessageFilter::DidGenerateCacheableMetadataInCacheStorage(
-    const GURL& url,
-    base::Time expected_response_time,
-    const std::vector<uint8_t>& data,
-    const url::Origin& cache_storage_origin,
-    const std::string& cache_storage_cache_name) {
-  scoped_refptr<net::IOBuffer> buf =
-      base::MakeRefCounted<net::IOBuffer>(data.size());
-  if (!data.empty())
-    memcpy(buf->data(), &data.front(), data.size());
-
-  cache_storage_context_->cache_manager()->OpenCache(
-      cache_storage_origin, CacheStorageOwner::kCacheAPI,
-      cache_storage_cache_name,
-      base::BindOnce(&RenderMessageFilter::OnCacheStorageOpenCallback,
-                     weak_ptr_factory_.GetWeakPtr(), url,
-                     expected_response_time, buf, data.size()));
-}
-
-void RenderMessageFilter::OnCacheStorageOpenCallback(
-    const GURL& url,
-    base::Time expected_response_time,
-    scoped_refptr<net::IOBuffer> buf,
-    int buf_len,
-    CacheStorageCacheHandle cache_handle,
-    CacheStorageError error) {
-  if (error != CacheStorageError::kSuccess || !cache_handle.value())
-    return;
-  CacheStorageCache* cache = cache_handle.value();
-  cache->WriteSideData(
-      base::BindOnce(&NoOpCacheStorageErrorCallback, std::move(cache_handle)),
-      url, expected_response_time, buf, buf_len);
-}
-
 void RenderMessageFilter::OnMediaLogEvents(
     const std::vector<media::MediaLogEvent>& events) {
   // OnMediaLogEvents() is always dispatched to the UI thread for handling.
@@ -352,23 +204,4 @@
   GpuProcessHost::GetHasGpuProcess(std::move(callback));
 }
 
-void RenderMessageFilter::DidGenerateCacheableMetadataOnUI(
-    const GURL& url,
-    base::Time expected_response_time,
-    const std::vector<uint8_t>& data) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  RenderProcessHost* host = RenderProcessHost::FromID(render_process_id_);
-  if (!host)
-    return;
-
-  // Use the same priority for the metadata write as for script
-  // resources (see defaultPriorityForResourceType() in WebKit's
-  // CachedResource.cpp). Note that WebURLRequest::PriorityMedium
-  // corresponds to net::LOW (see ConvertWebKitPriorityToNetPriority()
-  // in weburlloader_impl.cc).
-  const net::RequestPriority kPriority = net::LOW;
-  host->GetStoragePartition()->GetNetworkContext()->WriteCacheMetadata(
-      url, kPriority, expected_response_time, data);
-}
-
 }  // namespace content
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 58aa169..925508c 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -42,23 +42,15 @@
 }
 
 namespace net {
-class IOBuffer;
 class URLRequestContextGetter;
 }
 
-namespace url {
-class Origin;
-}
-
 namespace content {
 class BrowserContext;
-class CacheStorageContextImpl;
-class CacheStorageCacheHandle;
 class MediaInternals;
 class RenderWidgetHelper;
 class ResourceContext;
 class ResourceDispatcherHostImpl;
-class GeneratedCodeCacheContext;
 
 // This class filters out incoming IPC messages for the renderer process on the
 // IPC thread.
@@ -72,9 +64,7 @@
                       BrowserContext* browser_context,
                       net::URLRequestContextGetter* request_context,
                       RenderWidgetHelper* render_widget_helper,
-                      MediaInternals* media_internals,
-                      CacheStorageContextImpl* cache_storage_context,
-                      GeneratedCodeCacheContext* generated_code_cache_context);
+                      MediaInternals* media_internals);
 
   // BrowserMessageFilter methods:
   bool OnMessageReceived(const IPC::Message& message) override;
@@ -101,17 +91,6 @@
   void CreateFullscreenWidget(int opener_id,
                               mojom::WidgetPtr widget,
                               CreateFullscreenWidgetCallback callback) override;
-  void DidGenerateCacheableMetadata(const GURL& url,
-                                    base::Time expected_response_time,
-                                    const std::vector<uint8_t>& data) override;
-  void FetchCachedCode(const GURL& url, FetchCachedCodeCallback) override;
-  void ClearCodeCacheEntry(const GURL& url) override;
-  void DidGenerateCacheableMetadataInCacheStorage(
-      const GURL& url,
-      base::Time expected_response_time,
-      const std::vector<uint8_t>& data,
-      const url::Origin& cache_storage_origin,
-      const std::string& cache_storage_cache_name) override;
   void HasGpuProcess(HasGpuProcessCallback callback) override;
 #if defined(OS_LINUX)
   void SetThreadPriority(int32_t ns_tid,
@@ -125,25 +104,11 @@
                                      base::ThreadPriority priority);
 #endif
 
-  void OnReceiveCachedCode(FetchCachedCodeCallback callback,
-                           const base::Time& response_time,
-                           const std::vector<uint8_t>& data);
-  void OnCacheStorageOpenCallback(const GURL& url,
-                                  base::Time expected_response_time,
-                                  scoped_refptr<net::IOBuffer> buf,
-                                  int buf_len,
-                                  CacheStorageCacheHandle cache_handle,
-                                  blink::mojom::CacheStorageError error);
   void OnMediaLogEvents(const std::vector<media::MediaLogEvent>&);
 
   bool CheckBenchmarkingEnabled() const;
   bool CheckPreparsedJsCachingEnabled() const;
 
-  // NetworkContext must be called from the UI thread.
-  void DidGenerateCacheableMetadataOnUI(const GURL& url,
-                                        base::Time expected_response_time,
-                                        const std::vector<uint8_t>& data);
-
   // Cached resource request dispatcher host, guaranteed to be non-null. We do
   // not own it; it is managed by the BrowserProcess, which has a wider scope
   // than we do.
@@ -160,11 +125,6 @@
   int render_process_id_;
 
   MediaInternals* media_internals_;
-  CacheStorageContextImpl* cache_storage_context_;
-
-  // TODO(crbug.com/867347): Consider registering its own Mojo interface rather
-  // than going through RenderMessageFilter.
-  GeneratedCodeCacheContext* generated_code_cache_context_;
 
   base::WeakPtrFactory<RenderMessageFilter> weak_ptr_factory_;
 
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index ceeeff4..295511e 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -85,6 +85,8 @@
 #include "content/browser/cache_storage/cache_storage_context_impl.h"
 #include "content/browser/cache_storage/cache_storage_dispatcher_host.h"
 #include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/code_cache/generated_code_cache.h"
+#include "content/browser/code_cache/generated_code_cache_context.h"
 #include "content/browser/compositor/surface_utils.h"
 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
 #include "content/browser/dom_storage/dom_storage_message_filter.h"
@@ -112,6 +114,7 @@
 #include "content/browser/permissions/permission_service_impl.h"
 #include "content/browser/push_messaging/push_messaging_manager.h"
 #include "content/browser/renderer_host/clipboard_host_impl.h"
+#include "content/browser/renderer_host/code_cache_host_impl.h"
 #include "content/browser/renderer_host/embedded_frame_sink_provider_impl.h"
 #include "content/browser/renderer_host/file_utilities_host_impl.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
@@ -1955,14 +1958,10 @@
 
   scoped_refptr<net::URLRequestContextGetter> request_context(
       storage_partition_impl_->GetURLRequestContext());
-  // TODO(crbug.com/867347): Consider registering Mojo interface for
-  // GeneratedCodeCache rather than going through RenderMessageFilter.
   scoped_refptr<RenderMessageFilter> render_message_filter =
       base::MakeRefCounted<RenderMessageFilter>(
           GetID(), GetBrowserContext(), request_context.get(),
-          widget_helper_.get(), media_internals,
-          storage_partition_impl_->GetCacheStorageContext(),
-          storage_partition_impl_->GetGeneratedCodeCacheContext());
+          widget_helper_.get(), media_internals);
   AddFilter(render_message_filter.get());
 
   render_frame_message_filter_ = new RenderFrameMessageFilter(
@@ -2046,6 +2045,16 @@
                      origin));
 }
 
+void RenderProcessHostImpl::BindFileSystemManager(
+    blink::mojom::FileSystemManagerRequest request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::IO},
+      base::BindOnce(&FileSystemManagerImpl::BindRequest,
+                     base::Unretained(file_system_manager_impl_.get()),
+                     std::move(request)));
+}
+
 void RenderProcessHostImpl::CancelProcessShutdownDelayForUnload() {
   if (IsKeepAliveRefCountDisabled())
     return;
@@ -2162,8 +2171,14 @@
                  base::Unretained(push_messaging_manager_.get())));
 
   file_system_manager_impl_.reset(new FileSystemManagerImpl(
-      GetID(), storage_partition_impl_->GetFileSystemContext(),
+      GetID(), MSG_ROUTING_NONE,
+      storage_partition_impl_->GetFileSystemContext(),
       ChromeBlobStorageContext::GetFor(GetBrowserContext())));
+  // This interface is still exposed by the RenderProcessHost's registry so
+  // that it can be accessed by PepperFileSystemHost. Blink accesses this
+  // interface through RenderFrameHost/RendererInterfaceBinders.
+  // TODO(https://crbug.com/873661): Make PepperFileSystemHost access this with
+  // the RenderFrameHost's registry, and remove this registration.
   registry->AddInterface(
       base::BindRepeating(&FileSystemManagerImpl::BindRequest,
                           base::Unretained(file_system_manager_impl_.get())));
@@ -2203,6 +2218,12 @@
   registry->AddInterface(
       base::Bind(&metrics::CreateSingleSampleMetricsProvider));
 
+  registry->AddInterface(base::BindRepeating(
+      &CodeCacheHostImpl::Create, GetID(),
+      base::RetainedRef(storage_partition_impl_->GetCacheStorageContext()),
+      base::RetainedRef(
+          storage_partition_impl_->GetGeneratedCodeCacheContext())));
+
 #if BUILDFLAG(ENABLE_REPORTING)
   registry->AddInterface(
       base::Bind(&CreateReportingServiceProxy, storage_partition_impl_));
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index f49cb41..5778c10 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -59,6 +59,7 @@
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
 #include "third_party/blink/public/mojom/associated_interfaces/associated_interfaces.mojom.h"
 #include "third_party/blink/public/mojom/dom_storage/storage_partition_service.mojom.h"
+#include "third_party/blink/public/mojom/filesystem/file_system.mojom.h"
 #include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gl/gpu_switching_observer.h"
@@ -448,6 +449,9 @@
   // before the process shuts down.
   void DelayProcessShutdownForUnload(const base::TimeDelta& timeout);
 
+  // Binds request to the FileSystemManager instance owned by the render process
+  // host, and is used by workers via RendererInterfaceBinders.
+  void BindFileSystemManager(blink::mojom::FileSystemManagerRequest request);
   FileSystemManagerImpl* GetFileSystemManagerForTesting() {
     return file_system_manager_impl_.get();
   }
diff --git a/content/browser/renderer_host/render_view_host_delegate_view.cc b/content/browser/renderer_host/render_view_host_delegate_view.cc
index 746ea59..ac2f6c6 100644
--- a/content/browser/renderer_host/render_view_host_delegate_view.cc
+++ b/content/browser/renderer_host/render_view_host_delegate_view.cc
@@ -21,7 +21,7 @@
   return 0;
 }
 
-bool RenderViewHostDelegateView::DoBrowserControlsShrinkBlinkSize() const {
+bool RenderViewHostDelegateView::DoBrowserControlsShrinkRendererSize() const {
   return false;
 }
 
diff --git a/content/browser/renderer_host/render_view_host_delegate_view.h b/content/browser/renderer_host/render_view_host_delegate_view.h
index 62e97446..3b77252 100644
--- a/content/browser/renderer_host/render_view_host_delegate_view.h
+++ b/content/browser/renderer_host/render_view_host_delegate_view.h
@@ -80,8 +80,8 @@
   // Returns the height of the bottom controls in DIP.
   virtual int GetBottomControlsHeight() const;
 
-  // Returns true if the browser controls resize Blink's view size.
-  virtual bool DoBrowserControlsShrinkBlinkSize() const;
+  // Returns true if the browser controls resize the renderer's view size.
+  virtual bool DoBrowserControlsShrinkRendererSize() const;
 
   // Do post-event tasks for gesture events.
   virtual void GestureEventAck(const blink::WebGestureEvent& event,
diff --git a/content/browser/renderer_host/render_widget_host_delegate.cc b/content/browser/renderer_host/render_widget_host_delegate.cc
index e5ea12e..82ce021 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.cc
+++ b/content/browser/renderer_host/render_widget_host_delegate.cc
@@ -12,6 +12,10 @@
 
 namespace content {
 
+bool RenderWidgetHostDelegate::DoBrowserControlsShrinkRendererSize() const {
+  return false;
+}
+
 int RenderWidgetHostDelegate::GetTopControlsHeight() const {
   return 0;
 }
diff --git a/content/browser/renderer_host/render_widget_host_delegate.h b/content/browser/renderer_host/render_widget_host_delegate.h
index fb8cf2e..477dcc3 100644
--- a/content/browser/renderer_host/render_widget_host_delegate.h
+++ b/content/browser/renderer_host/render_widget_host_delegate.h
@@ -59,6 +59,7 @@
   // Functions for controlling the browser top controls slide behavior with page
   // gesture scrolling.
   virtual void SetTopControlsShownRatio(float ratio) {}
+  virtual bool DoBrowserControlsShrinkRendererSize() const;
   virtual int GetTopControlsHeight() const;
   virtual void SetTopControlsGestureScrollInProgress(bool in_progress) {}
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 9d5cd65..0b14202 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -812,7 +812,7 @@
       visual_properties->bottom_controls_height *= device_scale;
     }
     visual_properties->browser_controls_shrink_blink_size =
-        view_->DoBrowserControlsShrinkBlinkSize();
+        view_->DoBrowserControlsShrinkRendererSize();
     visual_properties->visible_viewport_size = view_->GetVisibleViewportSize();
     // TODO(ccameron): GetLocalSurfaceId is not synchronized with the device
     // scale factor of the surface. Fix this.
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index c0460f0..4e3782f 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -514,9 +514,9 @@
   return view_.GetPhysicalBackingSize();
 }
 
-bool RenderWidgetHostViewAndroid::DoBrowserControlsShrinkBlinkSize() const {
+bool RenderWidgetHostViewAndroid::DoBrowserControlsShrinkRendererSize() const {
   auto* delegate_view = GetRenderViewHostDelegateView();
-  return delegate_view ? delegate_view->DoBrowserControlsShrinkBlinkSize()
+  return delegate_view ? delegate_view->DoBrowserControlsShrinkRendererSize()
                        : false;
 }
 
@@ -1566,7 +1566,7 @@
 void RenderWidgetHostViewAndroid::TransformPointToRootSurface(
     gfx::PointF* point) {
   *point += gfx::Vector2d(
-      0, DoBrowserControlsShrinkBlinkSize() ? GetTopControlsHeight() : 0);
+      0, DoBrowserControlsShrinkRendererSize() ? GetTopControlsHeight() : 0);
 }
 
 // TODO(jrg): Find out the implications and answer correctly here,
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h
index 6d3920e..286904c 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.h
+++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -119,7 +119,7 @@
       base::OnceCallback<void(const SkBitmap&)> callback) override;
   void EnsureSurfaceSynchronizedForLayoutTest() override;
   uint32_t GetCaptureSequenceNumber() const override;
-  bool DoBrowserControlsShrinkBlinkSize() const override;
+  bool DoBrowserControlsShrinkRendererSize() const override;
   float GetTopControlsHeight() const override;
   float GetBottomControlsHeight() const override;
   int GetMouseWheelMinimumGranularity() const override;
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 3df0ea6..95444b0 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -838,9 +838,9 @@
   return latest_capture_sequence_number_;
 }
 
-bool RenderWidgetHostViewAura::DoBrowserControlsShrinkBlinkSize() const {
-  return !top_controls_gesture_scroll_in_progress_ &&
-         top_controls_shown_ratio_ > 0;
+bool RenderWidgetHostViewAura::DoBrowserControlsShrinkRendererSize() const {
+  return host()->delegate() &&
+         host()->delegate()->DoBrowserControlsShrinkRendererSize();
 }
 
 float RenderWidgetHostViewAura::GetTopControlsHeight() const {
@@ -996,11 +996,9 @@
   const blink::WebInputEvent::Type event_type = event.GetType();
   if (event_type == blink::WebGestureEvent::kGestureScrollBegin ||
       event_type == blink::WebGestureEvent::kGestureScrollEnd) {
-    top_controls_gesture_scroll_in_progress_ =
-        event_type == blink::WebGestureEvent::kGestureScrollBegin;
     if (host()->delegate()) {
       host()->delegate()->SetTopControlsGestureScrollInProgress(
-          top_controls_gesture_scroll_in_progress_);
+          event_type == blink::WebGestureEvent::kGestureScrollBegin);
     }
   }
 
@@ -2094,9 +2092,10 @@
     const cc::RenderFrameMetadata& metadata) {
   DCHECK(window_);
 
-  top_controls_shown_ratio_ = metadata.top_controls_shown_ratio;
-  if (host()->delegate())
-    host()->delegate()->SetTopControlsShownRatio(top_controls_shown_ratio_);
+  if (host()->delegate()) {
+    host()->delegate()->SetTopControlsShownRatio(
+        metadata.top_controls_shown_ratio);
+  }
 
   SynchronizeVisualProperties(cc::DeadlinePolicy::UseDefaultDeadline(),
                               metadata.local_surface_id);
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index f9625ed..cfb4918a 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -137,7 +137,7 @@
   void SetTooltipText(const base::string16& tooltip_text) override;
   void DisplayTooltipText(const base::string16& tooltip_text) override;
   uint32_t GetCaptureSequenceNumber() const override;
-  bool DoBrowserControlsShrinkBlinkSize() const override;
+  bool DoBrowserControlsShrinkRendererSize() const override;
   float GetTopControlsHeight() const override;
   bool IsSurfaceAvailableForCopy() const override;
   void CopyFromSurface(
@@ -569,9 +569,6 @@
   // Tracks the ancestors of the RWHVA window for window location changes.
   std::unique_ptr<WindowAncestorObserver> ancestor_window_observer_;
 
-  float top_controls_shown_ratio_ = 0.f;
-  bool top_controls_gesture_scroll_in_progress_ = false;
-
   // Are we in the process of closing?  Tracked so fullscreen views can avoid
   // sending a second shutdown request to the host when they lose the focus
   // after requesting shutdown for another reason (e.g. Escape key).
diff --git a/content/browser/renderer_host/render_widget_host_view_base.cc b/content/browser/renderer_host/render_widget_host_view_base.cc
index 7c8f4aab..dd63f89 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.cc
+++ b/content/browser/renderer_host/render_widget_host_view_base.cc
@@ -125,7 +125,7 @@
                                 GetDeviceScaleFactor());
 }
 
-bool RenderWidgetHostViewBase::DoBrowserControlsShrinkBlinkSize() const {
+bool RenderWidgetHostViewBase::DoBrowserControlsShrinkRendererSize() const {
   return false;
 }
 
diff --git a/content/browser/renderer_host/render_widget_host_view_base.h b/content/browser/renderer_host/render_widget_host_view_base.h
index fe8db96..31fbb90 100644
--- a/content/browser/renderer_host/render_widget_host_view_base.h
+++ b/content/browser/renderer_host/render_widget_host_view_base.h
@@ -229,9 +229,9 @@
   // The size of the view's backing surface in non-DPI-adjusted pixels.
   virtual gfx::Size GetCompositorViewportPixelSize() const;
 
-  // Whether or not Blink's viewport size should be shrunk by the height of the
-  // URL-bar.
-  virtual bool DoBrowserControlsShrinkBlinkSize() const;
+  // Whether or not the renderer's viewport size should be shrunk by the height
+  // of the URL-bar.
+  virtual bool DoBrowserControlsShrinkRendererSize() const;
 
   // The height of the URL-bar browser controls.
   virtual float GetTopControlsHeight() const;
diff --git a/content/browser/renderer_interface_binders.cc b/content/browser/renderer_interface_binders.cc
index c3a8bdc..f017a37 100644
--- a/content/browser/renderer_interface_binders.cc
+++ b/content/browser/renderer_interface_binders.cc
@@ -149,6 +149,13 @@
         static_cast<RenderProcessHostImpl*>(host)->BindCacheStorage(
             std::move(request), origin);
       }));
+  // TODO(https://crbug.com/873661): Pass origin to FileSystemMananger.
+  parameterized_binder_registry_.AddInterface(base::BindRepeating(
+      [](blink::mojom::FileSystemManagerRequest request,
+         RenderProcessHost* host, const url::Origin& origin) {
+        static_cast<RenderProcessHostImpl*>(host)->BindFileSystemManager(
+            std::move(request));
+      }));
   parameterized_binder_registry_.AddInterface(
       base::Bind([](blink::mojom::PermissionServiceRequest request,
                     RenderProcessHost* host, const url::Origin& origin) {
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 09f197b..1dbfe83 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -22,11 +22,13 @@
 #include "base/memory/ref_counted.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
+#include "base/no_destructor.h"
 #include "base/process/process.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
@@ -2104,6 +2106,10 @@
     delegate_->SetTopControlsShownRatio(this, ratio);
 }
 
+bool WebContentsImpl::DoBrowserControlsShrinkRendererSize() const {
+  return delegate_ && delegate_->DoBrowserControlsShrinkRendererSize(this);
+}
+
 int WebContentsImpl::GetTopControlsHeight() const {
   return delegate_ ? delegate_->GetTopControlsHeight() : 0;
 }
@@ -5085,6 +5091,31 @@
                                                    context_menu_params);
 }
 
+namespace {
+// Normalizes the line endings: \r\n -> \n, lone \r -> \n.
+base::string16 NormalizeLineBreaks(const base::string16& source) {
+  static const base::NoDestructor<base::string16> kReturnNewline(
+      base::ASCIIToUTF16("\r\n"));
+  static const base::NoDestructor<base::string16> kReturn(
+      base::ASCIIToUTF16("\r"));
+  static const base::NoDestructor<base::string16> kNewline(
+      base::ASCIIToUTF16("\n"));
+
+  std::vector<base::StringPiece16> pieces;
+
+  for (const auto& rn_line : base::SplitStringPieceUsingSubstr(
+           source, *kReturnNewline, base::KEEP_WHITESPACE,
+           base::SPLIT_WANT_ALL)) {
+    auto r_lines = base::SplitStringPieceUsingSubstr(
+        rn_line, *kReturn, base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+    std::move(std::begin(r_lines), std::end(r_lines),
+              std::back_inserter(pieces));
+  }
+
+  return base::JoinString(pieces, *kNewline);
+}
+}  // namespace
+
 void WebContentsImpl::RunJavaScriptDialog(RenderFrameHost* render_frame_host,
                                           const base::string16& message,
                                           const base::string16& default_prompt,
@@ -5134,16 +5165,19 @@
 
   is_showing_javascript_dialog_ = true;
 
+  base::string16 normalized_message = NormalizeLineBreaks(message);
+
   for (auto* handler : page_handlers) {
     handler->DidRunJavaScriptDialog(
-        render_frame_host->GetLastCommittedURL(), message, default_prompt,
-        dialog_type, has_non_devtools_handlers,
+        render_frame_host->GetLastCommittedURL(), normalized_message,
+        default_prompt, dialog_type, has_non_devtools_handlers,
         base::BindOnce(&CloseDialogCallbackWrapper::Run, wrapper, false));
   }
 
   if (dialog_manager_) {
     dialog_manager_->RunJavaScriptDialog(
-        this, render_frame_host, dialog_type, message, default_prompt,
+        this, render_frame_host, dialog_type, normalized_message,
+        default_prompt,
         base::BindOnce(&CloseDialogCallbackWrapper::Run, wrapper, false),
         &suppress_this_message);
   }
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 1260b590..511f9db 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -694,6 +694,7 @@
 
   ukm::SourceId GetUkmSourceIdForLastCommittedSource() const override;
   void SetTopControlsShownRatio(float ratio) override;
+  bool DoBrowserControlsShrinkRendererSize() const override;
   int GetTopControlsHeight() const override;
   void SetTopControlsGestureScrollInProgress(bool in_progress) override;
   void RenderWidgetCreated(RenderWidgetHostImpl* render_widget_host) override;
@@ -1038,6 +1039,8 @@
   FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
                            JavaScriptDialogsInMainAndSubframes);
   FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
+                           JavaScriptDialogsNormalizeText);
+  FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
                            DialogsFromJavaScriptEndFullscreen);
   FRIEND_TEST_ALL_PREFIXES(WebContentsImplBrowserTest,
                            DialogsFromJavaScriptEndFullscreenEvenInInnerWC);
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 8a65a08..13e32d0 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -1730,6 +1730,26 @@
 }
 
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+                       JavaScriptDialogsNormalizeText) {
+  WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents());
+  TestWCDelegateForDialogsAndFullscreen test_delegate;
+  wc->SetDelegate(&test_delegate);
+
+  GURL url("about:blank");
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+
+  // A dialog with mixed linebreaks.
+  std::string alert = "alert('1\\r2\\r\\n3\\n4')";
+  test_delegate.WillWaitForDialog();
+  EXPECT_TRUE(content::ExecuteScript(wc, alert));
+  test_delegate.Wait();
+  EXPECT_EQ("1\n2\n3\n4", test_delegate.last_message());
+
+  wc->SetDelegate(nullptr);
+  wc->SetJavaScriptDialogManagerForTesting(nullptr);
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
                        CreateWebContentsWithRendererProcess) {
   ASSERT_TRUE(embedded_test_server()->Start());
   WebContents* base_web_contents = shell()->web_contents();
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc
index 58f0a9d..097eb03 100644
--- a/content/browser/web_contents/web_contents_view_android.cc
+++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -521,9 +521,10 @@
   return delegate ? delegate->GetBottomControlsHeight() : 0;
 }
 
-bool WebContentsViewAndroid::DoBrowserControlsShrinkBlinkSize() const {
+bool WebContentsViewAndroid::DoBrowserControlsShrinkRendererSize() const {
   auto* delegate = web_contents_->GetDelegate();
-  return delegate ? delegate->DoBrowserControlsShrinkBlinkSize() : false;
+  return delegate &&
+         delegate->DoBrowserControlsShrinkRendererSize(web_contents_);
 }
 
 bool WebContentsViewAndroid::OnTouchEvent(const ui::MotionEventAndroid& event) {
diff --git a/content/browser/web_contents/web_contents_view_android.h b/content/browser/web_contents/web_contents_view_android.h
index 58bb78c..37358129 100644
--- a/content/browser/web_contents/web_contents_view_android.h
+++ b/content/browser/web_contents/web_contents_view_android.h
@@ -107,7 +107,7 @@
   void TakeFocus(bool reverse) override;
   int GetTopControlsHeight() const override;
   int GetBottomControlsHeight() const override;
-  bool DoBrowserControlsShrinkBlinkSize() const override;
+  bool DoBrowserControlsShrinkRendererSize() const override;
 
   // ui::EventHandlerAndroid implementation.
   bool OnTouchEvent(const ui::MotionEventAndroid& event) override;
diff --git a/content/common/common_param_traits_unittest.cc b/content/common/common_param_traits_unittest.cc
index 4d4ee04..7c395a8 100644
--- a/content/common/common_param_traits_unittest.cc
+++ b/content/common/common_param_traits_unittest.cc
@@ -256,9 +256,9 @@
   content::RenderWidgetSurfaceProperties input;
   input.size = gfx::Size(23, 45);
   input.device_scale_factor = 0.8;
-#ifdef OS_ANDROID
   input.top_controls_height = 16.5;
   input.top_controls_shown_ratio = 0.4;
+#ifdef OS_ANDROID
   input.bottom_controls_height = 23.4;
   input.bottom_controls_shown_ratio = 0.8;
   input.selection.start.set_type(gfx::SelectionBound::Type::CENTER);
@@ -275,9 +275,9 @@
 
   EXPECT_EQ(input.size, output.size);
   EXPECT_EQ(input.device_scale_factor, output.device_scale_factor);
-#ifdef OS_ANDROID
   EXPECT_EQ(input.top_controls_height, output.top_controls_height);
   EXPECT_EQ(input.top_controls_shown_ratio, output.top_controls_shown_ratio);
+#ifdef OS_ANDROID
   EXPECT_EQ(input.bottom_controls_height, output.bottom_controls_height);
   EXPECT_EQ(input.bottom_controls_shown_ratio,
             output.bottom_controls_shown_ratio);
diff --git a/content/common/content_param_traits_macros.h b/content/common/content_param_traits_macros.h
index f9bbe75..a2c4c7a 100644
--- a/content/common/content_param_traits_macros.h
+++ b/content/common/content_param_traits_macros.h
@@ -69,9 +69,9 @@
 IPC_STRUCT_TRAITS_BEGIN(content::RenderWidgetSurfaceProperties)
   IPC_STRUCT_TRAITS_MEMBER(size)
   IPC_STRUCT_TRAITS_MEMBER(device_scale_factor)
-#ifdef OS_ANDROID
   IPC_STRUCT_TRAITS_MEMBER(top_controls_height)
   IPC_STRUCT_TRAITS_MEMBER(top_controls_shown_ratio)
+#ifdef OS_ANDROID
   IPC_STRUCT_TRAITS_MEMBER(bottom_controls_height)
   IPC_STRUCT_TRAITS_MEMBER(bottom_controls_shown_ratio)
   IPC_STRUCT_TRAITS_MEMBER(selection)
diff --git a/content/common/font_cache_dispatcher_win.cc b/content/common/font_cache_dispatcher_win.cc
index 9337781..680062d 100644
--- a/content/common/font_cache_dispatcher_win.cc
+++ b/content/common/font_cache_dispatcher_win.cc
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "base/thread_annotations.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/service_manager/public/cpp/bind_source_info.h"
 
@@ -125,8 +126,8 @@
   FontCache() {
   }
 
-  std::map<base::string16, CacheElement> cache_;
-  DispatcherToFontNames dispatcher_font_map_;
+  std::map<base::string16, CacheElement> cache_ GUARDED_BY(mutex_);
+  DispatcherToFontNames dispatcher_font_map_ GUARDED_BY(mutex_);
   base::Lock mutex_;
 
   DISALLOW_COPY_AND_ASSIGN(FontCache);
diff --git a/content/common/plugin_list.h b/content/common/plugin_list.h
index 35ff2d0..a76f0a6 100644
--- a/content/common/plugin_list.h
+++ b/content/common/plugin_list.h
@@ -15,6 +15,7 @@
 #include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "base/synchronization/lock.h"
+#include "base/thread_annotations.h"
 #include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "content/public/common/webplugininfo.h"
@@ -122,7 +123,8 @@
 
   // Removes |plugin_path| from the list of extra plugin paths. Should only be
   // called while holding |lock_|.
-  void RemoveExtraPluginPathLocked(const base::FilePath& plugin_path);
+  void RemoveExtraPluginPathLocked(const base::FilePath& plugin_path)
+      EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Creates a WebPluginInfo structure given a plugin's path.  On success
   // returns true, with the information being put into "info".
@@ -142,19 +144,19 @@
   // States whether we will load the plugin list the next time we try to access
   // it, whether we are currently in the process of loading it, or whether we
   // consider it up to date.
-  LoadingState loading_state_;
+  LoadingState loading_state_ GUARDED_BY(lock_);
 
   // Extra plugin paths that we want to search when loading.
-  std::vector<base::FilePath> extra_plugin_paths_;
+  std::vector<base::FilePath> extra_plugin_paths_ GUARDED_BY(lock_);
 
   // Holds information about internal plugins.
-  std::vector<WebPluginInfo> internal_plugins_;
+  std::vector<WebPluginInfo> internal_plugins_ GUARDED_BY(lock_);
 
   // A list holding all plugins.
-  std::vector<WebPluginInfo> plugins_list_;
+  std::vector<WebPluginInfo> plugins_list_ GUARDED_BY(lock_);
 
   // Callback that is invoked whenever the PluginList will reload the plugins.
-  base::Closure will_load_plugins_callback_;
+  base::Closure will_load_plugins_callback_ GUARDED_BY(lock_);
 
   // Need synchronization for the above members since this object can be
   // accessed on multiple threads.
diff --git a/content/common/render_message_filter.mojom b/content/common/render_message_filter.mojom
index c31715ab..c83c5d0 100644
--- a/content/common/render_message_filter.mojom
+++ b/content/common/render_message_filter.mojom
@@ -25,25 +25,6 @@
   [Sync] CreateFullscreenWidget(int32 opener_id, Widget widget)
       => (int32 route_id);
 
-  // Requests that the browser cache |data| associated with |url| and |expected_response_time|.
-  // TODO(https://crbug.com/779444): Verify or remove |url| and |cache_storage_origin|.
-  DidGenerateCacheableMetadata(url.mojom.Url url,
-                               mojo_base.mojom.Time expected_response_time,
-                               array<uint8> data);
-
-  // TODO(crbug.com/867848) Pass the data as mojo data_pipe instead of
-  // array<unit8>.
-  FetchCachedCode(url.mojom.Url url) => (mojo_base.mojom.Time response_time,
-                                         array<uint8> data);
-
-  ClearCodeCacheEntry(url.mojom.Url url);
-
-  // Requests that the browser cache |data| for the specified CacheStorage entry.
-  DidGenerateCacheableMetadataInCacheStorage(
-      url.mojom.Url url, mojo_base.mojom.Time expected_response_time,
-      array<uint8> data, url.mojom.Origin cache_storage_origin,
-      string cache_storage_cache_name);
-
   // A renderer sends this when it wants to know whether a gpu process exists.
   [Sync] HasGpuProcess() => (bool has_gpu_process);
 
diff --git a/content/common/render_widget_surface_properties.cc b/content/common/render_widget_surface_properties.cc
index 2848b01..09a9a0d 100644
--- a/content/common/render_widget_surface_properties.cc
+++ b/content/common/render_widget_surface_properties.cc
@@ -13,9 +13,9 @@
   RenderWidgetSurfaceProperties properties;
   properties.size = frame.size_in_pixels();
   properties.device_scale_factor = frame.device_scale_factor();
-#ifdef OS_ANDROID
   properties.top_controls_height = frame.metadata.top_controls_height;
   properties.top_controls_shown_ratio = frame.metadata.top_controls_shown_ratio;
+#ifdef OS_ANDROID
   properties.bottom_controls_height = frame.metadata.bottom_controls_height;
   properties.bottom_controls_shown_ratio =
       frame.metadata.bottom_controls_shown_ratio;
@@ -39,9 +39,9 @@
 bool RenderWidgetSurfaceProperties::operator==(
     const RenderWidgetSurfaceProperties& other) const {
   return other.device_scale_factor == device_scale_factor &&
-#ifdef OS_ANDROID
          other.top_controls_height == top_controls_height &&
          other.top_controls_shown_ratio == top_controls_shown_ratio &&
+#ifdef OS_ANDROID
          other.bottom_controls_height == bottom_controls_height &&
          other.bottom_controls_shown_ratio == bottom_controls_shown_ratio &&
          other.selection == selection &&
@@ -77,7 +77,6 @@
     ++changed_properties;
   }
 
-#ifdef OS_ANDROID
   if (top_controls_height != other.top_controls_height) {
     if (changed_properties > 0)
       stream << ", ";
@@ -94,6 +93,8 @@
     ++changed_properties;
   }
 
+#ifdef OS_ANDROID
+
   if (bottom_controls_height != other.bottom_controls_height) {
     if (changed_properties > 0)
       stream << ", ";
diff --git a/content/common/render_widget_surface_properties.h b/content/common/render_widget_surface_properties.h
index da357db..c30cf77e 100644
--- a/content/common/render_widget_surface_properties.h
+++ b/content/common/render_widget_surface_properties.h
@@ -30,9 +30,9 @@
 
   gfx::Size size;
   float device_scale_factor = 0;
-#ifdef OS_ANDROID
   float top_controls_height = 0;
   float top_controls_shown_ratio = 0;
+#ifdef OS_ANDROID
   float bottom_controls_height = 0;
   float bottom_controls_shown_ratio = 0;
   viz::Selection<gfx::SelectionBound> selection;
diff --git a/content/common/service_manager/service_manager_connection_impl.cc b/content/common/service_manager/service_manager_connection_impl.cc
index dac316d..5c5eca5 100644
--- a/content/common/service_manager/service_manager_connection_impl.cc
+++ b/content/common/service_manager/service_manager_connection_impl.cc
@@ -14,6 +14,7 @@
 #include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop_current.h"
+#include "base/thread_annotations.h"
 #include "base/threading/thread_checker.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
@@ -339,14 +340,15 @@
 
   std::unique_ptr<service_manager::ServiceContext> service_context_;
   mojo::BindingSet<service_manager::mojom::ServiceFactory> factory_bindings_;
-  int next_filter_id_ = kInvalidConnectionFilterId;
 
   // Not owned.
   MessageLoopObserver* message_loop_observer_ = nullptr;
 
-  // Guards |connection_filters_|.
+  // Guards |connection_filters_| and |next_filter_id_|.
   base::Lock lock_;
-  std::map<int, std::unique_ptr<ConnectionFilter>> connection_filters_;
+  std::map<int, std::unique_ptr<ConnectionFilter>> connection_filters_
+      GUARDED_BY(lock_);
+  int next_filter_id_ GUARDED_BY(lock_) = kInvalidConnectionFilterId;
 
   std::map<std::string, std::unique_ptr<service_manager::EmbeddedServiceRunner>>
       embedded_services_;
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 0ccb69f..03d96205 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -43,6 +43,7 @@
           "blink.mojom.BlobRegistry",
           "blink.mojom.BroadcastChannelProvider",
           "blink.mojom.ClipboardHost",
+          "blink.mojom.CodeCacheHost",
           "blink.mojom.FontUniqueNameLookup",
           "blink.mojom.EmbeddedFrameSinkProvider",
           "blink.mojom.FileUtilitiesHost",
@@ -162,6 +163,7 @@
           "blink.mojom.CredentialManager",
           "blink.mojom.DisplayCutoutHost",
           "blink.mojom.DedicatedWorkerFactory",
+          "blink.mojom.FileSystemManager",
           "blink.mojom.LockManager",
           "blink.mojom.GeolocationService",
           "blink.mojom.InsecureInputService",
@@ -227,6 +229,7 @@
         "renderer": [
           "blink.mojom.CacheStorage",
           "blink.mojom.DedicatedWorkerFactory",
+          "blink.mojom.FileSystemManager",
           "blink.mojom.LockManager",
           "blink.mojom.NotificationService",
           "blink.mojom.PermissionService",
@@ -263,6 +266,7 @@
       "provides": {
         "renderer": [
           "blink.mojom.CacheStorage",
+          "blink.mojom.FileSystemManager",
           "blink.mojom.LockManager",
           "blink.mojom.NotificationService",
           "blink.mojom.PermissionService",
diff --git a/content/public/app/mojo/content_renderer_manifest.json b/content/public/app/mojo/content_renderer_manifest.json
index 4ae4abe..d048cbc 100644
--- a/content/public/app/mojo/content_renderer_manifest.json
+++ b/content/public/app/mojo/content_renderer_manifest.json
@@ -5,6 +5,7 @@
     "service_manager:connector": {
       "provides": {
         "browser": [
+          "blink.mojom.CodeCacheHost",
           "blink.mojom.CrashMemoryMetricsReporter",
           "blink.mojom.LeakDetector",
           "blink.mojom.OomIntervention",
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index c7cf40ef..86ec98a 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -256,7 +256,8 @@
   return 0;
 }
 
-bool WebContentsDelegate::DoBrowserControlsShrinkBlinkSize() const {
+bool WebContentsDelegate::DoBrowserControlsShrinkRendererSize(
+    const WebContents* web_contents) const {
   return false;
 }
 
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index 23107c8..1c9c817 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -563,7 +563,8 @@
   // needed by embedder because it's always accompanied by view size change.
   virtual int GetTopControlsHeight() const;
   virtual int GetBottomControlsHeight() const;
-  virtual bool DoBrowserControlsShrinkBlinkSize() const;
+  virtual bool DoBrowserControlsShrinkRendererSize(
+      const WebContents* web_contents) const;
 
   // Propagates to the browser that gesture scrolling has changed state. This is
   // used by the browser to assist in controlling the behavior of sliding the
diff --git a/content/public/test/android/dom_utils.cc b/content/public/test/android/dom_utils.cc
index f6b3f75..71f8059a 100644
--- a/content/public/test/android/dom_utils.cc
+++ b/content/public/test/android/dom_utils.cc
@@ -24,7 +24,7 @@
   // Android obtains the top control size via WebContentsDelegate.
   WebContentsDelegate* delegate = web_contents->GetDelegate();
   float scale = web_contents->GetNativeView()->GetDipScale();
-  return delegate && delegate->DoBrowserControlsShrinkBlinkSize()
+  return delegate && delegate->DoBrowserControlsShrinkRendererSize(web_contents)
              ? delegate->GetTopControlsHeight() * scale
              : 0;
 }
diff --git a/content/public/test/browsing_data_remover_test_util.cc b/content/public/test/browsing_data_remover_test_util.cc
index 3d6492c..2ea2ab6 100644
--- a/content/public/test/browsing_data_remover_test_util.cc
+++ b/content/public/test/browsing_data_remover_test_util.cc
@@ -6,12 +6,14 @@
 
 #include "base/bind.h"
 #include "base/task/task_scheduler/task_scheduler.h"
+#include "base/threading/thread_task_runner_handle.h"
 
 namespace content {
 
 BrowsingDataRemoverCompletionObserver::BrowsingDataRemoverCompletionObserver(
     BrowsingDataRemover* remover)
-    : observer_(this) {
+    : observer_(this),
+      origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
   observer_.Add(remover);
 }
 
@@ -20,10 +22,7 @@
 
 void BrowsingDataRemoverCompletionObserver::BlockUntilCompletion() {
   base::TaskScheduler::GetInstance()->FlushAsyncForTesting(base::BindOnce(
-      [](BrowsingDataRemoverCompletionObserver* observer) {
-        observer->flush_for_testing_complete_ = true;
-        observer->QuitRunLoopWhenTasksComplete();
-      },
+      &BrowsingDataRemoverCompletionObserver::FlushForTestingComplete,
       base::Unretained(this)));
   run_loop_.Run();
 }
@@ -34,6 +33,19 @@
   QuitRunLoopWhenTasksComplete();
 }
 
+void BrowsingDataRemoverCompletionObserver::FlushForTestingComplete() {
+  if (origin_task_runner_->RunsTasksInCurrentSequence()) {
+    flush_for_testing_complete_ = true;
+    QuitRunLoopWhenTasksComplete();
+    return;
+  }
+  origin_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &BrowsingDataRemoverCompletionObserver::FlushForTestingComplete,
+          base::Unretained(this)));
+}
+
 void BrowsingDataRemoverCompletionObserver::QuitRunLoopWhenTasksComplete() {
   if (!flush_for_testing_complete_ || !browsing_data_remover_done_)
     return;
@@ -43,7 +55,9 @@
 
 BrowsingDataRemoverCompletionInhibitor::BrowsingDataRemoverCompletionInhibitor(
     BrowsingDataRemover* remover)
-    : remover_(remover), run_loop_(new base::RunLoop) {
+    : remover_(remover),
+      run_loop_(new base::RunLoop),
+      origin_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
   DCHECK(remover);
   remover_->SetWouldCompleteCallbackForTesting(
       base::Bind(&BrowsingDataRemoverCompletionInhibitor::
@@ -66,10 +80,7 @@
 
 void BrowsingDataRemoverCompletionInhibitor::BlockUntilNearCompletion() {
   base::TaskScheduler::GetInstance()->FlushAsyncForTesting(base::BindOnce(
-      [](BrowsingDataRemoverCompletionInhibitor* inhibitor) {
-        inhibitor->flush_for_testing_complete_ = true;
-        inhibitor->QuitRunLoopWhenTasksComplete();
-      },
+      &BrowsingDataRemoverCompletionInhibitor::FlushForTestingComplete,
       base::Unretained(this)));
   run_loop_->Run();
   run_loop_ = std::make_unique<base::RunLoop>();
@@ -91,6 +102,19 @@
   QuitRunLoopWhenTasksComplete();
 }
 
+void BrowsingDataRemoverCompletionInhibitor::FlushForTestingComplete() {
+  if (origin_task_runner_->RunsTasksInCurrentSequence()) {
+    flush_for_testing_complete_ = true;
+    QuitRunLoopWhenTasksComplete();
+    return;
+  }
+  origin_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          &BrowsingDataRemoverCompletionInhibitor::FlushForTestingComplete,
+          base::Unretained(this)));
+}
+
 void BrowsingDataRemoverCompletionInhibitor::QuitRunLoopWhenTasksComplete() {
   if (!flush_for_testing_complete_ ||
       !browsing_data_remover_would_complete_done_) {
diff --git a/content/public/test/browsing_data_remover_test_util.h b/content/public/test/browsing_data_remover_test_util.h
index 4d31980..eaf96d7 100644
--- a/content/public/test/browsing_data_remover_test_util.h
+++ b/content/public/test/browsing_data_remover_test_util.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "base/scoped_observer.h"
+#include "base/sequenced_task_runner.h"
 #include "content/public/browser/browsing_data_remover.h"
 
 namespace content {
@@ -29,6 +30,7 @@
   void OnBrowsingDataRemoverDone() override;
 
  private:
+  void FlushForTestingComplete();
   void QuitRunLoopWhenTasksComplete();
 
   // Tracks when the Task Scheduler task flushing is done.
@@ -40,6 +42,7 @@
 
   base::RunLoop run_loop_;
   ScopedObserver<BrowsingDataRemover, BrowsingDataRemover::Observer> observer_;
+  scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowsingDataRemoverCompletionObserver);
 };
@@ -66,6 +69,7 @@
       const base::Closure& continue_to_completion);
 
  private:
+  void FlushForTestingComplete();
   void QuitRunLoopWhenTasksComplete();
 
   // Tracks when the Task Scheduler task flushing is done.
@@ -80,6 +84,7 @@
 
   std::unique_ptr<base::RunLoop> run_loop_;
   base::Closure continue_to_completion_callback_;
+  scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowsingDataRemoverCompletionInhibitor);
 };
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index 53f3b5b..a546049 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -64,28 +64,6 @@
     NOTREACHED();
   }
 
-  void DidGenerateCacheableMetadata(const GURL& url,
-                                    base::Time expected_response_time,
-                                    const std::vector<uint8_t>& data) override {
-    NOTREACHED();
-  }
-
-  void FetchCachedCode(const GURL& url,
-                       FetchCachedCodeCallback callback) override {
-    NOTREACHED();
-  }
-
-  void ClearCodeCacheEntry(const GURL& url) override { NOTREACHED(); }
-
-  void DidGenerateCacheableMetadataInCacheStorage(
-      const GURL& url,
-      base::Time expected_response_time,
-      const std::vector<uint8_t>& data,
-      const url::Origin& cache_storage_origin,
-      const std::string& cache_storage_cache_name) override {
-    NOTREACHED();
-  }
-
   void HasGpuProcess(HasGpuProcessCallback callback) override {
     std::move(callback).Run(false);
   }
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index f7b9445..70cb730 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -170,7 +170,10 @@
 }
 
 RenderViewTest::RenderViewTest() {
-  RenderFrameImpl::InstallCreateHook(&TestRenderFrame::CreateTestRenderFrame);
+  // Overrides creation of RenderFrameImpl, but does not need to
+  // override behaviour of WebWidgetClient.
+  RenderFrameImpl::InstallCreateHook(&TestRenderFrame::CreateTestRenderFrame,
+                                     nullptr, nullptr);
 }
 
 RenderViewTest::~RenderViewTest() {
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 7baa128..2a06cc4 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -109,10 +109,6 @@
     "fetchers/multi_resolution_image_resource_fetcher.h",
     "fetchers/resource_fetcher_impl.cc",
     "fetchers/resource_fetcher_impl.h",
-    "fileapi/file_system_dispatcher.cc",
-    "fileapi/file_system_dispatcher.h",
-    "fileapi/webfilesystem_impl.cc",
-    "fileapi/webfilesystem_impl.h",
     "frame_blame_context.cc",
     "frame_blame_context.h",
     "frame_owner_properties.cc",
diff --git a/content/renderer/fileapi/OWNERS b/content/renderer/fileapi/OWNERS
deleted file mode 100644
index 6269c8b3..0000000
--- a/content/renderer/fileapi/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-file://content/browser/fileapi/OWNERS
-
-# TEAM: storage-dev@chromium.org
-# COMPONENT: Blink>Storage>FileSystem
diff --git a/content/renderer/fileapi/file_system_dispatcher.cc b/content/renderer/fileapi/file_system_dispatcher.cc
deleted file mode 100644
index d8cd6a7..0000000
--- a/content/renderer/fileapi/file_system_dispatcher.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/fileapi/file_system_dispatcher.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/callback.h"
-#include "base/files/file_util.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/no_destructor.h"
-#include "base/process/process.h"
-#include "components/services/filesystem/public/interfaces/types.mojom.h"
-#include "content/child/child_thread_impl.h"
-#include "content/public/common/service_names.mojom.h"
-#include "content/public/renderer/worker_thread.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "storage/common/fileapi/file_system_info.h"
-#include "storage/common/fileapi/file_system_type_converters.h"
-
-namespace content {
-
-FileSystemDispatcher::FileSystemDispatcher(
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
-    : main_thread_task_runner_(std::move(main_thread_task_runner)) {}
-
-FileSystemDispatcher::~FileSystemDispatcher() = default;
-
-blink::mojom::FileSystemManager& FileSystemDispatcher::GetFileSystemManager() {
-  auto BindInterfaceOnMainThread =
-      [](blink::mojom::FileSystemManagerRequest request) {
-        DCHECK(ChildThreadImpl::current());
-        ChildThreadImpl::current()->GetConnector()->BindInterface(
-            mojom::kBrowserServiceName, std::move(request));
-      };
-  if (!file_system_manager_ptr_) {
-    if (WorkerThread::GetCurrentId()) {
-      blink::mojom::FileSystemManagerRequest request =
-          mojo::MakeRequest(&file_system_manager_ptr_);
-      main_thread_task_runner_->PostTask(
-          FROM_HERE,
-          base::BindOnce(BindInterfaceOnMainThread, std::move(request)));
-    } else {
-      BindInterfaceOnMainThread(mojo::MakeRequest(&file_system_manager_ptr_));
-    }
-  }
-  return *file_system_manager_ptr_;
-}
-
-void FileSystemDispatcher::ChooseEntry(
-    int render_frame_id,
-    std::unique_ptr<ChooseEntryCallbacks> callbacks) {
-  GetFileSystemManager().ChooseEntry(
-      render_frame_id,
-      base::BindOnce(
-          [](std::unique_ptr<ChooseEntryCallbacks> callbacks,
-             base::File::Error result,
-             std::vector<blink::mojom::FileSystemEntryPtr> entries) {
-            if (result != base::File::FILE_OK) {
-              callbacks->OnError(result);
-            } else {
-              blink::WebVector<blink::WebFileSystem::FileSystemEntry>
-                  web_entries(entries.size());
-              for (size_t i = 0; i < entries.size(); ++i) {
-                web_entries[i].file_system_id =
-                    blink::WebString::FromASCII(entries[i]->file_system_id);
-                web_entries[i].base_name =
-                    blink::WebString::FromASCII(entries[i]->base_name);
-              }
-              callbacks->OnSuccess(std::move(web_entries));
-            }
-          },
-          std::move(callbacks)));
-}
-
-}  // namespace content
diff --git a/content/renderer/fileapi/file_system_dispatcher.h b/content/renderer/fileapi/file_system_dispatcher.h
deleted file mode 100644
index b5df614..0000000
--- a/content/renderer/fileapi/file_system_dispatcher.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_FILEAPI_FILE_SYSTEM_DISPATCHER_H_
-#define CONTENT_RENDERER_FILEAPI_FILE_SYSTEM_DISPATCHER_H_
-
-#include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/mojom/filesystem/file_system.mojom.h"
-#include "third_party/blink/public/platform/web_file_system.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}  // namespace base
-
-namespace content {
-
-// Dispatches and sends file system related messages sent to/from a child
-// process from/to the main browser process. There is an instance held by
-// each WebFileSystemImpl object.
-// TODO(adithyas): Move functionality to blink::FileSystemDispatcher and
-// remove this class.
-class FileSystemDispatcher {
- public:
-  explicit FileSystemDispatcher(
-      scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
-  ~FileSystemDispatcher();
-
-  using ChooseEntryCallbacks = blink::WebFileSystem::ChooseEntryCallbacks;
-  void ChooseEntry(int render_frame_id,
-                   std::unique_ptr<ChooseEntryCallbacks> callbacks);
-
- private:
-  blink::mojom::FileSystemManager& GetFileSystemManager();
-
-  blink::mojom::FileSystemManagerPtr file_system_manager_ptr_;
-  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
-
-  DISALLOW_COPY_AND_ASSIGN(FileSystemDispatcher);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_FILEAPI_FILE_SYSTEM_DISPATCHER_H_
diff --git a/content/renderer/fileapi/webfilesystem_impl.cc b/content/renderer/fileapi/webfilesystem_impl.cc
deleted file mode 100644
index b471ad4..0000000
--- a/content/renderer/fileapi/webfilesystem_impl.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/fileapi/webfilesystem_impl.h"
-
-#include "base/lazy_instance.h"
-#include "base/threading/thread_local.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "content/public/renderer/render_frame.h"
-#include "content/renderer/fileapi/file_system_dispatcher.h"
-#include "content/renderer/render_thread_impl.h"
-#include "third_party/blink/public/web/web_frame.h"
-
-namespace content {
-
-namespace {
-
-base::LazyInstance<base::ThreadLocalPointer<WebFileSystemImpl>>::Leaky
-    g_webfilesystem_tls = LAZY_INSTANCE_INITIALIZER;
-
-enum CallbacksUnregisterMode {
-  UNREGISTER_CALLBACKS,
-  DO_NOT_UNREGISTER_CALLBACKS,
-};
-
-}  // namespace
-
-//-----------------------------------------------------------------------------
-// WebFileSystemImpl
-
-WebFileSystemImpl* WebFileSystemImpl::ThreadSpecificInstance(
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner) {
-  if (g_webfilesystem_tls.Pointer()->Get() || !main_thread_task_runner)
-    return g_webfilesystem_tls.Pointer()->Get();
-  WebFileSystemImpl* filesystem =
-      new WebFileSystemImpl(std::move(main_thread_task_runner));
-  if (WorkerThread::GetCurrentId())
-    WorkerThread::AddObserver(filesystem);
-  return filesystem;
-}
-
-void WebFileSystemImpl::DeleteThreadSpecificInstance() {
-  DCHECK(!WorkerThread::GetCurrentId());
-  if (g_webfilesystem_tls.Pointer()->Get())
-    delete g_webfilesystem_tls.Pointer()->Get();
-}
-
-WebFileSystemImpl::WebFileSystemImpl(
-    scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner)
-    : main_thread_task_runner_(main_thread_task_runner),
-      file_system_dispatcher_(std::move(main_thread_task_runner)) {
-  g_webfilesystem_tls.Pointer()->Set(this);
-}
-
-WebFileSystemImpl::~WebFileSystemImpl() {
-  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-  g_webfilesystem_tls.Pointer()->Set(nullptr);
-}
-
-void WebFileSystemImpl::WillStopCurrentWorkerThread() {
-  delete this;
-}
-
-void WebFileSystemImpl::ChooseEntry(
-    blink::WebFrame* frame,
-    std::unique_ptr<ChooseEntryCallbacks> callbacks) {
-  file_system_dispatcher_.ChooseEntry(
-      RenderFrame::GetRoutingIdForWebFrame(frame), std::move(callbacks));
-}
-
-}  // namespace content
diff --git a/content/renderer/fileapi/webfilesystem_impl.h b/content/renderer/fileapi/webfilesystem_impl.h
deleted file mode 100644
index a3c2ecf86..0000000
--- a/content/renderer/fileapi/webfilesystem_impl.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_FILEAPI_WEBFILESYSTEM_IMPL_H_
-#define CONTENT_RENDERER_FILEAPI_WEBFILESYSTEM_IMPL_H_
-
-#include "base/memory/ref_counted.h"
-#include "base/threading/thread_checker.h"
-#include "content/public/renderer/worker_thread.h"
-#include "content/renderer/fileapi/file_system_dispatcher.h"
-#include "third_party/blink/public/platform/web_file_system.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace content {
-
-// TODO(adithyas): Move functionality to blink::FileSystemDispatcher and remove
-// this class.
-class WebFileSystemImpl : public blink::WebFileSystem,
-                          public WorkerThread::Observer {
- public:
-  // Returns thread-specific instance.  If non-null |main_thread_loop|
-  // is given and no thread-specific instance has been created it may
-  // create a new instance.
-  static WebFileSystemImpl* ThreadSpecificInstance(
-      scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
-
-  // Deletes thread-specific instance (if exists). For workers it deletes
-  // itself in WillStopCurrentWorkerThread(), but for an instance created on the
-  // main thread this method must be called.
-  static void DeleteThreadSpecificInstance();
-
-  explicit WebFileSystemImpl(
-      scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner);
-  ~WebFileSystemImpl() override;
-
-  // WorkerThread::Observer implementation.
-  void WillStopCurrentWorkerThread() override;
-
-  void ChooseEntry(blink::WebFrame* frame,
-                   std::unique_ptr<ChooseEntryCallbacks>) override;
-
- private:
-  scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
-  FileSystemDispatcher file_system_dispatcher_;
-
-  // Thread-affine per use of TLS in impl.
-  THREAD_CHECKER(thread_checker_);
-
-  DISALLOW_COPY_AND_ASSIGN(WebFileSystemImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_RENDERER_FILEAPI_WEBFILESYSTEM_IMPL_H_
diff --git a/content/renderer/gpu/gpu_benchmarking_extension.cc b/content/renderer/gpu/gpu_benchmarking_extension.cc
index ec157e0..7f9420a 100644
--- a/content/renderer/gpu/gpu_benchmarking_extension.cc
+++ b/content/renderer/gpu/gpu_benchmarking_extension.cc
@@ -457,8 +457,10 @@
   if (!base::PathIsWritable(path.DirName())) {
     std::string msg("Path is not writable: ");
     msg.append(path.DirName().MaybeAsASCII());
-    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
-        isolate, msg.c_str(), v8::String::kNormalString, msg.length())));
+    isolate->ThrowException(v8::Exception::Error(
+        v8::String::NewFromUtf8(isolate, msg.c_str(),
+                                v8::NewStringType::kNormal, msg.length())
+            .ToLocalChecked()));
     return;
   }
   SkFILEWStream wStream(path.MaybeAsASCII().c_str());
@@ -607,8 +609,10 @@
   PrintDocumentTofile(isolate, filename, &MakeXPSDocument);
 #else
   std::string msg("PrintPagesToXPS is unsupported.");
-  isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
-      isolate, msg.c_str(), v8::String::kNormalString, msg.length())));
+  isolate->ThrowException(v8::Exception::Error(
+      v8::String::NewFromUtf8(isolate, msg.c_str(), v8::NewStringType::kNormal,
+                              msg.length())
+          .ToLocalChecked()));
 #endif
 }
 
@@ -627,8 +631,10 @@
       !base::PathIsWritable(dirpath)) {
     std::string msg("Path is not writable: ");
     msg.append(dirpath.MaybeAsASCII());
-    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
-        isolate, msg.c_str(), v8::String::kNormalString, msg.length())));
+    isolate->ThrowException(v8::Exception::Error(
+        v8::String::NewFromUtf8(isolate, msg.c_str(),
+                                v8::NewStringType::kNormal, msg.length())
+            .ToLocalChecked()));
     return;
   }
 
diff --git a/content/renderer/pepper/pepper_file_system_host.cc b/content/renderer/pepper/pepper_file_system_host.cc
index 53915df..2622490 100644
--- a/content/renderer/pepper/pepper_file_system_host.cc
+++ b/content/renderer/pepper/pepper_file_system_host.cc
@@ -10,7 +10,6 @@
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/renderer/render_view.h"
 #include "content/public/renderer/renderer_ppapi_host.h"
-#include "content/renderer/fileapi/file_system_dispatcher.h"
 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
 #include "content/renderer/render_thread_impl.h"
 #include "ppapi/c/pp_errors.h"
diff --git a/content/renderer/pepper/v8_var_converter.cc b/content/renderer/pepper/v8_var_converter.cc
index 5c4319d..93cdbdc 100644
--- a/content/renderer/pepper/v8_var_converter.cc
+++ b/content/renderer/pepper/v8_var_converter.cc
@@ -130,8 +130,10 @@
       // in the sense that string primitives in JavaScript can't be referenced
       // in the same way that string vars can in pepper. But that information
       // isn't very useful and primitive strings are a more expected form in JS.
-      *result = v8::String::NewFromUtf8(
-          isolate, value.c_str(), v8::String::kNormalString, value.size());
+      *result =
+          v8::String::NewFromUtf8(isolate, value.c_str(),
+                                  v8::NewStringType::kNormal, value.size())
+              .ToLocalChecked();
       break;
     }
     case PP_VARTYPE_ARRAY_BUFFER: {
@@ -419,10 +421,11 @@
         if (did_create && CanHaveChildren(child_var))
           stack.push_back(child_var);
         v8::TryCatch try_catch(isolate);
-        v8_object->Set(
-            v8::String::NewFromUtf8(
-                isolate, key.c_str(), v8::String::kNormalString, key.length()),
-            child_v8);
+        v8_object->Set(v8::String::NewFromUtf8(isolate, key.c_str(),
+                                               v8::NewStringType::kInternalized,
+                                               key.length())
+                           .ToLocalChecked(),
+                       child_v8);
         if (try_catch.HasCaught()) {
           LOG(ERROR) << "Setter for property " << key.c_str() << " threw an "
                      << "exception.";
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 8bc7bb1..381b4a9 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -585,6 +585,10 @@
 
 RenderFrameImpl::CreateRenderFrameImplFunction g_create_render_frame_impl =
     nullptr;
+RenderFrameImpl::CreateRenderWidgetForChildLocalRootFunction
+    g_create_render_widget = nullptr;
+RenderFrameImpl::RenderWidgetForChildLocalRootInitializedCallback
+    g_render_widget_initialized = nullptr;
 
 WebString ConvertRelativePathToHtmlAttribute(const base::FilePath& path) {
   DCHECK(!path.IsAbsolute());
@@ -1285,12 +1289,25 @@
       replicated_state.frame_policy.sandbox_flags);
   if (has_committed_real_load)
     web_frame->SetCommittedFirstRealLoad();
-  render_frame->render_widget_ = RenderWidget::CreateForFrame(
-      widget_routing_id, hidden, screen_info, compositor_deps, web_frame);
-  // TODO(avi): This DCHECK is to track cleanup for https://crbug.com/545684
-  DCHECK_EQ(render_view->GetWidget(), render_frame->render_widget_)
-      << "Main frame is no longer reusing the RenderView as its widget! "
-      << "Does the RenderFrame need to register itself with the RenderWidget?";
+
+  // The RenderViewImpl and its RenderWidget already exist by the time we get
+  // here.
+  // TODO(crbug.com/419087): We probably want to create the RenderWidget here
+  // though (when we make the WebFrameWidget?).
+  RenderWidget* render_widget = render_view->GetWidget();
+
+  // Non-owning pointer that is self-referencing and destroyed by calling
+  // Close(). The RenderViewImpl has a RenderWidget already, but not a
+  // WebFrameWidget, which is now attached here.
+  auto* web_frame_widget = blink::WebFrameWidget::CreateForMainFrame(
+      render_view->WidgetClient(), web_frame);
+  render_view->AttachWebFrameWidget(web_frame_widget);
+  // TODO(crbug.com/419087): This was added in 6ccadf770766e89c3 to prevent an
+  // empty ScreenInfo, but the WebView has already been created and initialized
+  // by RenderViewImpl, so this is surely redundant?
+  render_widget->UpdateWebViewWithDeviceScaleFactor();
+
+  render_frame->render_widget_ = render_widget;
   render_frame->in_frame_tree_ = true;
   return render_frame;
 }
@@ -1309,8 +1326,12 @@
     const mojom::CreateFrameWidgetParams& widget_params,
     const FrameOwnerProperties& frame_owner_properties,
     bool has_committed_real_load) {
-  blink::WebLocalFrame* web_frame;
-  RenderFrameImpl* render_frame;
+  // TODO(danakj): Split this method into two pieces. The first block makes a
+  // WebLocalFrame and collects the RenderView and RenderFrame for it. The
+  // second block uses that to make/setup a RenderWidget, if needed.
+  RenderViewImpl* render_view = nullptr;
+  RenderFrameImpl* render_frame = nullptr;
+  blink::WebLocalFrame* web_frame = nullptr;
   if (proxy_routing_id == MSG_ROUTING_NONE) {
     // TODO(alexmos): This path is currently used only:
     // 1) When recreating a RenderFrame after a crash.
@@ -1332,6 +1353,7 @@
     if (previous_sibling_proxy)
       previous_sibling_web_frame = previous_sibling_proxy->web_frame();
 
+    render_view = parent_proxy->render_view();
     // Create the RenderFrame and WebLocalFrame, linking the two.
     render_frame = RenderFrameImpl::Create(
         parent_proxy->render_view(), routing_id, std::move(interface_provider),
@@ -1362,7 +1384,15 @@
     if (!proxy)
       return;
 
-    render_frame = RenderFrameImpl::Create(proxy->render_view(), routing_id,
+    // This path is creating a local frame. It may or may not be a local root,
+    // depending if the frame's parent is local or remote. It may also be the
+    // main frame, as in the case where a navigation to the current process'
+    // origin replaces a remote main frame (the proxy's web_frame()) with a
+    // local one.
+    const bool proxy_is_main_frame = !proxy->web_frame()->Parent();
+
+    render_view = proxy->render_view();
+    render_frame = RenderFrameImpl::Create(render_view, routing_id,
                                            std::move(interface_provider),
                                            devtools_frame_token);
     render_frame->InitializeBlameContext(nullptr);
@@ -1372,16 +1402,119 @@
         render_frame, render_frame->blink_interface_registry_.get(),
         proxy->web_frame(), replicated_state.frame_policy.sandbox_flags,
         replicated_state.frame_policy.container_policy);
+    // The new |web_frame| is a main frame iff the proxy's frame was.
+    DCHECK_EQ(proxy_is_main_frame, !web_frame->Parent());
   }
-  CHECK(parent_routing_id != MSG_ROUTING_NONE || !web_frame->Parent());
 
-  if (widget_params.routing_id != MSG_ROUTING_NONE) {
-    // TODO(fsamuel): It's not clear if we should be passing in the
-    // web ScreenInfo or the original ScreenInfo here.
-    render_frame->render_widget_ = RenderWidget::CreateForFrame(
-        widget_params.routing_id, widget_params.hidden,
-        render_frame->render_view_->GetWebScreenInfo(), compositor_deps,
-        web_frame);
+  DCHECK(render_view);
+  DCHECK(render_frame);
+  DCHECK(web_frame);
+
+  const bool is_main_frame = !web_frame->Parent();
+
+  // Child frames require there to be a |parent_routing_id| present, for the
+  // remote parent frame. Though it is only used if the |proxy_routing_id| is
+  // not given, which happens in some corner cases.
+  if (!is_main_frame)
+    DCHECK_NE(parent_routing_id, MSG_ROUTING_NONE);
+
+  // We now have a WebLocalFrame for the new frame. The next step is to set
+  // up a RenderWidget for it, if it is needed.
+  //
+  // If there is no widget routing id, then the new frame is not a local root,
+  // and does not need a RenderWidget. In that case we'll do nothing. Otherwise
+  // it does.
+  if (is_main_frame) {
+    // For a main frame, we use the RenderWidget already attached to the
+    // RenderView (this is being changed by https://crbug.com/419087).
+
+    // Main frames are always local roots, so they should always have a routing
+    // id. Surprisingly, this routing id is *not* used though, as the routing id
+    // on the existing RenderWidget is not changed. (I don't know why.)
+    // TODO(crbug.com/888105): It's a bug that the RenderWidget is not using
+    // this routing id.
+    DCHECK_NE(widget_params.routing_id, MSG_ROUTING_NONE);
+
+    // The RenderViewImpl and its RenderWidget already exist by the time we
+    // get here (we get them from the RenderFrameProxy).
+    // TODO(crbug.com/419087): We probably want to create the RenderWidget
+    // here though (when we make the WebFrameWidget?).
+    RenderWidget* render_widget = render_view->GetWidget();
+
+    // Non-owning pointer that is self-referencing and destroyed by calling
+    // Close(). The RenderViewImpl has a RenderWidget already, but not a
+    // WebFrameWidget, which is now attached here.
+    auto* web_frame_widget = blink::WebFrameWidget::CreateForMainFrame(
+        render_view->WidgetClient(), web_frame);
+    render_view->AttachWebFrameWidget(web_frame_widget);
+    // TODO(crbug.com/419087): This was added in 6ccadf770766e89c3 to prevent
+    // an empty ScreenInfo, but the WebView has already been created and
+    // initialized by RenderViewImpl, so this is surely redundant? It will be
+    // pulling the device scale factor off the WebView itself.
+    render_widget->UpdateWebViewWithDeviceScaleFactor();
+
+    render_frame->render_widget_ = render_widget;
+  } else if (widget_params.routing_id != MSG_ROUTING_NONE) {
+    // This frame is a child local root, so we require a separate RenderWidget
+    // for it from any other frames in the frame tree. Each local root defines
+    // a separate context/coordinate space/world for compositing, painting,
+    // input, etc. And each local root has a RenderWidget which provides
+    // such services independent from other RenderWidgets.
+    // Notably, we do not attempt to reuse the main frame's RenderWidget (if the
+    // main frame in this frame tree is local) as that RenderWidget is
+    // functioning in a different local root. Because this is a child local
+    // root, it implies there is some remote frame ancestor between this frame
+    // and the main frame, thus its coordinate space etc is not known relative
+    // to the main frame.
+
+    // TODO(crbug.com/419087): This is grabbing something off the view's
+    // widget but if the main frame is remote this widget would not be valid?
+    const ScreenInfo& screen_info_from_main_frame =
+        render_view->GetWidget()->GetWebScreenInfo();
+
+    // Makes a new RenderWidget for the child local root. It provides the
+    // local root with a new compositing, painting, and input coordinate
+    // space/context.
+    scoped_refptr<RenderWidget> render_widget;
+    if (g_create_render_widget) {
+      // LayoutTest hooks inject a different type (subclass) for RenderWidget,
+      // allowing it to override the behaviour of the WebWidgetClient which
+      // RenderWidget provides.
+      render_widget = g_create_render_widget(
+          widget_params.routing_id, compositor_deps, WidgetType::kFrame,
+          screen_info_from_main_frame, blink::kWebDisplayModeUndefined,
+          /*swapped_out=*/false, widget_params.hidden,
+          /*never_visible=*/false);
+    } else {
+      render_widget = base::MakeRefCounted<RenderWidget>(
+          widget_params.routing_id, compositor_deps, WidgetType::kFrame,
+          screen_info_from_main_frame, blink::kWebDisplayModeUndefined,
+          /*swapped_out=*/false, widget_params.hidden,
+          /*never_visible=*/false);
+    }
+
+    // Non-owning pointer that is self-referencing and destroyed by calling
+    // Close(). We use the new RenderWidget as the client for this
+    // WebFrameWidget, *not* the RenderWidget of the MainFrame, which is
+    // accessible from the RenderViewImpl.
+    auto* web_frame_widget = blink::WebFrameWidget::CreateForChildLocalRoot(
+        render_widget.get(), web_frame);
+
+    // Adds a reference on RenderWidget, making it self-referencing. So it
+    // will not be destroyed by scoped_refptr unless Close() has been called
+    // and run.
+    render_widget->InitForChildLocalRoot(web_frame_widget);
+    // TODO(crbug.com/419087): This was added in 6ccadf770766e89c3 to prevent
+    // an empty ScreenInfo, but the WebView has already been created and
+    // initialized by RenderViewImpl, so this is surely redundant? It will be
+    // pulling the device scale factor off the WebView itself.
+    render_widget->UpdateWebViewWithDeviceScaleFactor();
+
+    // LayoutTest hooks to set up the injected type for RenderWidget.
+    if (g_render_widget_initialized)
+      g_render_widget_initialized(render_widget.get());
+
+    render_frame->render_widget_ = std::move(render_widget);
   }
 
   if (has_committed_real_load)
@@ -1425,9 +1558,15 @@
 
 // static
 void RenderFrameImpl::InstallCreateHook(
-    CreateRenderFrameImplFunction create_render_frame_impl) {
-  CHECK(!g_create_render_frame_impl);
-  g_create_render_frame_impl = create_render_frame_impl;
+    CreateRenderFrameImplFunction create_frame,
+    CreateRenderWidgetForChildLocalRootFunction create_widget,
+    RenderWidgetForChildLocalRootInitializedCallback widget_initialized) {
+  DCHECK(!g_create_render_frame_impl);
+  DCHECK(!g_create_render_widget);
+  DCHECK(!g_render_widget_initialized);
+  g_create_render_frame_impl = create_frame;
+  g_create_render_widget = create_widget;
+  g_render_widget_initialized = widget_initialized;
 }
 
 // static
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index 8323fa2..67a3f40d 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -47,6 +47,7 @@
 #include "content/public/common/renderer_preferences.h"
 #include "content/public/common/resource_type.h"
 #include "content/public/common/stop_find_action.h"
+#include "content/public/common/widget_type.h"
 #include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/websocket_handshake_throttle_provider.h"
 #include "content/renderer/content_security_policy_util.h"
@@ -270,8 +271,25 @@
   };
 
   using CreateRenderFrameImplFunction = RenderFrameImpl* (*)(CreateParams);
+  using CreateRenderWidgetForChildLocalRootFunction =
+      RenderWidget* (*)(int32_t,
+                        CompositorDependencies*,
+                        WidgetType,
+                        const ScreenInfo&,
+                        blink::WebDisplayMode display_mode,
+                        bool,
+                        bool,
+                        bool);
+  using RenderWidgetForChildLocalRootInitializedCallback =
+      void (*)(RenderWidget*);
+
+  // LayoutTests override the creation of RenderFrames and RenderWidgets in
+  // order to inject their own (subclass) type and change behaviour inside the
+  // tests.
   static void InstallCreateHook(
-      CreateRenderFrameImplFunction create_render_frame_impl);
+      CreateRenderFrameImplFunction create_frame,
+      CreateRenderWidgetForChildLocalRootFunction create_widget,
+      RenderWidgetForChildLocalRootInitializedCallback widget_initialized);
 
   // Looks up and returns the WebFrame corresponding to a given opener frame
   // routing ID.
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 23c95140..dd6dc88 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -88,8 +88,6 @@
 #include "content/renderer/dom_storage/webstoragearea_impl.h"
 #include "content/renderer/dom_storage/webstoragenamespace_impl.h"
 #include "content/renderer/effective_connection_type_helper.h"
-#include "content/renderer/fileapi/file_system_dispatcher.h"
-#include "content/renderer/fileapi/webfilesystem_impl.h"
 #include "content/renderer/gpu/frame_swap_message_queue.h"
 #include "content/renderer/indexed_db/indexed_db_dispatcher.h"
 #include "content/renderer/input/widget_input_handler_manager.h"
@@ -1011,7 +1009,6 @@
 
 void RenderThreadImpl::Shutdown() {
   ChildThreadImpl::Shutdown();
-  WebFileSystemImpl::DeleteThreadSpecificInstance();
   // In a multi-process mode, we immediately exit the renderer.
   // Historically we had a graceful shutdown sequence here but it was
   // 1) a waste of performance and 2) a source of lots of complicated
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 7036d48..beee71f 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -534,6 +534,10 @@
 
   ApplyBlinkSettings(command_line, webview()->GetSettings());
 
+  // We have either a main frame or a proxy routing id.
+  DCHECK_NE(params->main_frame_routing_id != MSG_ROUTING_NONE,
+            params->proxy_routing_id != MSG_ROUTING_NONE);
+
   if (params->main_frame_routing_id != MSG_ROUTING_NONE) {
     CHECK(params->main_frame_interface_provider.is_valid());
     service_manager::mojom::InterfaceProviderPtr main_frame_interface_provider(
@@ -545,12 +549,9 @@
         GetWidget()->GetWebScreenInfo(), GetWidget()->compositor_deps(),
         opener_frame, params->devtools_main_frame_token,
         params->replicated_frame_state, params->has_committed_real_load);
-  }
 
-  // TODO(dcheng): Shouldn't these be mutually exclusive at this point? See
-  // https://crbug.com/720116 where the browser is apparently sending both
-  // routing IDs...
-  if (params->proxy_routing_id != MSG_ROUTING_NONE) {
+    main_render_frame_->Initialize();
+  } else {
     CHECK(params->swapped_out);
     RenderFrameProxy::CreateFrameProxy(params->proxy_routing_id, GetRoutingID(),
                                        opener_frame, MSG_ROUTING_NONE,
@@ -558,9 +559,6 @@
                                        params->devtools_main_frame_token);
   }
 
-  if (main_render_frame_)
-    main_render_frame_->Initialize();
-
   // If this RenderView's creation was initiated by an opener page in this
   // process, (e.g. window.open()), we won't be visible until we ask the opener,
   // via |show_callback|, to make us visible. Otherwise, we went through a
@@ -1086,19 +1084,6 @@
     webview()->SetIsActive(active);
 }
 
-void RenderViewImpl::SetBackgroundOpaqueForWidget(bool opaque) {
-  if (!frame_widget_)
-    return;
-
-  if (opaque) {
-    frame_widget_->ClearBaseBackgroundColorOverride();
-    frame_widget_->ClearBackgroundColorOverride();
-  } else {
-    frame_widget_->SetBaseBackgroundColorOverride(SK_ColorTRANSPARENT);
-    frame_widget_->SetBackgroundColorOverride(SK_ColorTRANSPARENT);
-  }
-}
-
 bool RenderViewImpl::SupportsMultipleWindowsForWidget() {
   return webkit_preferences_.supports_multiple_windows;
 }
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index cd13b43..4338420 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -379,7 +379,6 @@
   bool RenderWidgetWillHandleMouseEventForWidget(
       const blink::WebMouseEvent& event) override;
   void SetActiveForWidget(bool active) override;
-  void SetBackgroundOpaqueForWidget(bool opaque) override;
   bool SupportsMultipleWindowsForWidget() override;
   void DidHandleGestureEventForWidget(
       const blink::WebGestureEvent& event) override;
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index f335a3c6..77f9bd6 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -335,12 +335,6 @@
   return result;
 }
 
-content::RenderWidget::CreateRenderWidgetFunction g_create_render_widget =
-    nullptr;
-
-content::RenderWidget::RenderWidgetInitializedCallback
-    g_render_widget_initialized = nullptr;
-
 ui::TextInputType ConvertWebTextInputType(blink::WebTextInputType type) {
   // Check the type is in the range representable by ui::TextInputType.
   DCHECK_LE(type, static_cast<int>(ui::TEXT_INPUT_TYPE_MAX))
@@ -388,7 +382,7 @@
 
 RenderWidget::RenderWidget(int32_t widget_routing_id,
                            CompositorDependencies* compositor_deps,
-                           WidgetType popup_type,
+                           WidgetType widget_type,
                            const ScreenInfo& screen_info,
                            blink::WebDisplayMode display_mode,
                            bool swapped_out,
@@ -415,7 +409,7 @@
       next_previous_flags_(kInvalidNextPreviousFlagsValue),
       can_compose_inline_(true),
       composition_range_(gfx::Range::InvalidRange()),
-      popup_type_(popup_type),
+      widget_type_(widget_type),
       pending_window_rect_count_(0),
       screen_info_(screen_info),
       monitor_composition_info_(false),
@@ -473,15 +467,6 @@
 }
 
 // static
-void RenderWidget::InstallCreateHook(
-    CreateRenderWidgetFunction create_render_widget,
-    RenderWidgetInitializedCallback render_widget_initialized) {
-  CHECK(!g_create_render_widget && !g_render_widget_initialized);
-  g_create_render_widget = create_render_widget;
-  g_render_widget_initialized = render_widget_initialized;
-}
-
-// static
 RenderWidget* RenderWidget::FromRoutingID(int32_t routing_id) {
   RoutingIDWidgetMap* widgets = g_routing_id_widget_map.Pointer();
   RoutingIDWidgetMap::iterator it = widgets->find(routing_id);
@@ -519,57 +504,12 @@
   return widget.get();
 }
 
-// static
-RenderWidget* RenderWidget::CreateForFrame(
-    int widget_routing_id,
-    bool hidden,
-    const ScreenInfo& screen_info,
-    CompositorDependencies* compositor_deps,
-    blink::WebLocalFrame* frame) {
-  CHECK_NE(widget_routing_id, MSG_ROUTING_NONE);
-  RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(frame);
-  // For the mainframe, the RenderWidget is attached to the RenderView.
-  // TODO(ajwong): Remove this when the widget is always attached to a frame.
-  // https://crbug.com/545684
-  if (!frame->Parent()) {
-    RenderViewImpl* view =
-        static_cast<RenderViewImpl*>(render_frame->GetRenderView());
-    // Use the WidgetClient() from the RenderViewImpl, rather than getting its
-    // RenderWidget directly. Layout tests may inject a different
-    // WebWidgetClient on the RenderViewImpl that intercepts calls before they
-    // get to the RenderWidget.
-    view->AttachWebFrameWidget(
-        RenderWidget::CreateWebFrameWidget(view->WidgetClient(), frame));
-    view->GetWidget()->UpdateWebViewWithDeviceScaleFactor();
-    return view->GetWidget();
-  }
-  scoped_refptr<RenderWidget> widget(
-      g_create_render_widget
-          ? g_create_render_widget(widget_routing_id, compositor_deps,
-                                   WidgetType::kFrame, screen_info,
-                                   blink::kWebDisplayModeUndefined, false,
-                                   hidden, false)
-          : new RenderWidget(widget_routing_id, compositor_deps,
-                             WidgetType::kFrame, screen_info,
-                             blink::kWebDisplayModeUndefined, false, hidden,
-                             false));
-  widget->for_oopif_ = true;
-  // Init increments the reference count on |widget|, keeping it alive after
-  // this function returns.
-  widget->Init(base::NullCallback(),
-               RenderWidget::CreateWebFrameWidget(widget.get(), frame));
-  widget->UpdateWebViewWithDeviceScaleFactor();
-
-  if (g_render_widget_initialized)
-    g_render_widget_initialized(widget.get());
-  return widget.get();
-}
-
-// static
-blink::WebFrameWidget* RenderWidget::CreateWebFrameWidget(
-    blink::WebWidgetClient* widget_client,
-    blink::WebLocalFrame* frame) {
-  return blink::WebFrameWidget::Create(widget_client, frame);
+void RenderWidget::InitForChildLocalRoot(
+    blink::WebFrameWidget* web_frame_widget) {
+  for_oopif_ = true;
+  // Init() increments the reference count on |this|, making it
+  // self-referencing.
+  Init(base::NullCallback(), web_frame_widget);
 }
 
 void RenderWidget::CloseForFrame() {
@@ -972,8 +912,24 @@
 }
 
 void RenderWidget::OnSetBackgroundOpaque(bool opaque) {
-  if (owner_delegate_)
-    owner_delegate_->SetBackgroundOpaqueForWidget(opaque);
+  // Background opaque-ness modification is only supported for the main frame.
+  // The |owner_delegate_| is used as proxy for this RenderWidget being attached
+  // to the main frame.
+  if (!owner_delegate_)
+    return;
+
+  blink::WebWidget* web_widget = GetWebWidget();
+  // This is true since we only do this for RenderWidgets attached to the main
+  // frame.
+  DCHECK(web_widget->IsWebFrameWidget());
+  auto* web_frame_widget = static_cast<blink::WebFrameWidget*>(web_widget);
+  if (opaque) {
+    web_frame_widget->ClearBaseBackgroundColorOverride();
+    web_frame_widget->ClearBackgroundColorOverride();
+  } else {
+    web_frame_widget->SetBaseBackgroundColorOverride(SK_ColorTRANSPARENT);
+    web_frame_widget->SetBackgroundColorOverride(SK_ColorTRANSPARENT);
+  }
 }
 
 void RenderWidget::OnSetFocus(bool enable) {
@@ -1797,7 +1753,7 @@
 
   // Popups don't get size updates back from the browser so just store the set
   // values.
-  if (popup_type_ != WidgetType::kFrame) {
+  if (widget_type_ != WidgetType::kFrame) {
     window_screen_rect_ = rect;
     view_screen_rect_ = rect;
   }
@@ -2001,7 +1957,7 @@
     const gfx::Rect& compositor_visible_rect,
     bool occluded_or_obscured) {
   if (auto* frame_widget = GetFrameWidget()) {
-    DCHECK_EQ(popup_type_, WidgetType::kFrame);
+    DCHECK_EQ(widget_type_, WidgetType::kFrame);
     compositor_visible_rect_ = compositor_visible_rect;
     frame_widget->SetRemoteViewportIntersection(viewport_intersection,
                                                 occluded_or_obscured);
@@ -2011,7 +1967,7 @@
 
 void RenderWidget::OnSetIsInert(bool inert) {
   if (auto* frame_widget = GetFrameWidget()) {
-    DCHECK_EQ(popup_type_, WidgetType::kFrame);
+    DCHECK_EQ(widget_type_, WidgetType::kFrame);
     frame_widget->SetIsInert(inert);
   }
 }
@@ -2019,7 +1975,7 @@
 void RenderWidget::OnSetInheritedEffectiveTouchAction(
     cc::TouchAction touch_action) {
   if (auto* frame_widget = GetFrameWidget()) {
-    DCHECK_EQ(popup_type_, WidgetType::kFrame);
+    DCHECK_EQ(widget_type_, WidgetType::kFrame);
     frame_widget->SetInheritedEffectiveTouchAction(touch_action);
   }
 }
@@ -2027,7 +1983,7 @@
 void RenderWidget::OnUpdateRenderThrottlingStatus(bool is_throttled,
                                                   bool subtree_throttled) {
   if (auto* frame_widget = GetFrameWidget()) {
-    DCHECK_EQ(popup_type_, WidgetType::kFrame);
+    DCHECK_EQ(widget_type_, WidgetType::kFrame);
     frame_widget->UpdateRenderThrottlingStatus(is_throttled, subtree_throttled);
   }
 }
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 8ce7c73..5a3c9a8 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -151,34 +151,32 @@
     TTFAP_5MIN_AFTER_BACKGROUNDED,
   };
 
+  // An Init*() method must be called after creating a RenderWidget, which will
+  // make the RenderWidget self-referencing. Then it can be deleted by calling
+  // Close().
+  RenderWidget(int32_t widget_routing_id,
+               CompositorDependencies* compositor_deps,
+               WidgetType widget_type,
+               const ScreenInfo& screen_info,
+               blink::WebDisplayMode display_mode,
+               bool swapped_out,
+               bool hidden,
+               bool never_visible,
+               mojom::WidgetRequest widget_request = nullptr);
+
   // Creates a new RenderWidget for a popup. |opener| is the RenderView that
   // this widget lives inside.
+  // TODO(danakj): Change this to InitForPopup() and use the public constructor
+  // from RenderViewImpl, moving code specific to that class out of the method.
   static RenderWidget* CreateForPopup(RenderViewImpl* opener,
                                       CompositorDependencies* compositor_deps,
                                       const ScreenInfo& screen_info);
 
-  // Creates a new RenderWidget that will be attached to a RenderFrame.
-  static RenderWidget* CreateForFrame(int widget_routing_id,
-                                      bool hidden,
-                                      const ScreenInfo& screen_info,
-                                      CompositorDependencies* compositor_deps,
-                                      blink::WebLocalFrame* frame);
-
-  // Used by content_layouttest_support to hook into the creation of
-  // RenderWidgets.
-  using CreateRenderWidgetFunction =
-      RenderWidget* (*)(int32_t,
-                        CompositorDependencies*,
-                        WidgetType,
-                        const ScreenInfo&,
-                        blink::WebDisplayMode display_mode,
-                        bool,
-                        bool,
-                        bool);
-  using RenderWidgetInitializedCallback = void (*)(RenderWidget*);
-  static void InstallCreateHook(
-      CreateRenderWidgetFunction create_render_widget,
-      RenderWidgetInitializedCallback render_widget_initialized_callback);
+  // Initialize a new RenderWidget that will be attached to a RenderFrame (via
+  // the WebFrameWidget), for a frame that is a local root, but not the main
+  // frame. This method increments the reference count on the RenderWidget,
+  // making it self-referencing, which can be released by calling Close().
+  void InitForChildLocalRoot(blink::WebFrameWidget* web_frame_widget);
 
   void set_owner_delegate(RenderWidgetOwnerDelegate* owner_delegate) {
     DCHECK(!owner_delegate_);
@@ -531,23 +529,8 @@
   base::WeakPtr<RenderWidget> AsWeakPtr();
 
  protected:
-  RenderWidget(int32_t widget_routing_id,
-               CompositorDependencies* compositor_deps,
-               WidgetType popup_type,
-               const ScreenInfo& screen_info,
-               blink::WebDisplayMode display_mode,
-               bool swapped_out,
-               bool hidden,
-               bool never_visible,
-               mojom::WidgetRequest widget_request = nullptr);
-
-  // Avoid making RenderWidget other than as a refptr.
   ~RenderWidget() override;
 
-  static blink::WebFrameWidget* CreateWebFrameWidget(
-      blink::WebWidgetClient* widget_client,
-      blink::WebLocalFrame* frame);
-
   // Called by Create() functions and subclasses to finish initialization.
   // |show_callback| will be invoked once WebWidgetClient::Show() occurs, and
   // should be null if Show() won't be triggered for this widget.
@@ -885,7 +868,7 @@
   gfx::Range composition_range_;
 
   // The kind of popup this widget represents, NONE if not a popup.
-  WidgetType popup_type_;
+  WidgetType widget_type_;
 
   // While we are waiting for the browser to update window sizes, we track the
   // pending size temporarily.
diff --git a/content/renderer/render_widget_owner_delegate.h b/content/renderer/render_widget_owner_delegate.h
index 2365a39..0b4a8af 100644
--- a/content/renderer/render_widget_owner_delegate.h
+++ b/content/renderer/render_widget_owner_delegate.h
@@ -33,9 +33,6 @@
   // See comment in RenderWidgetHost::SetActive().
   virtual void SetActiveForWidget(bool active) = 0;
 
-  // See comment in RenderWidgetHostImpl::SetBackgroundOpaque().
-  virtual void SetBackgroundOpaqueForWidget(bool opaque) = 0;
-
   // Returns whether multiple windows are allowed for the widget. If true, then
   // Show() may be called more than once.
   virtual bool SupportsMultipleWindowsForWidget() = 0;
diff --git a/content/renderer/render_widget_unittest.cc b/content/renderer/render_widget_unittest.cc
index 5fc7683e..cd4ee4a 100644
--- a/content/renderer/render_widget_unittest.cc
+++ b/content/renderer/render_widget_unittest.cc
@@ -468,7 +468,6 @@
     return false;
   }
   void SetActiveForWidget(bool active) override {}
-  void SetBackgroundOpaqueForWidget(bool opaque) override {}
   bool SupportsMultipleWindowsForWidget() override { return true; }
   void DidHandleGestureEventForWidget(
       const blink::WebGestureEvent& event) override {}
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 1b677f4..20e975e 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -33,7 +33,6 @@
 #include "content/child/thread_safe_sender.h"
 #include "content/common/frame_messages.h"
 #include "content/common/gpu_stream_constants.h"
-#include "content/common/render_message_filter.mojom.h"
 #include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/service_manager_connection.h"
@@ -47,7 +46,6 @@
 #include "content/renderer/dom_storage/local_storage_namespace.h"
 #include "content/renderer/dom_storage/session_web_storage_namespace_impl.h"
 #include "content/renderer/dom_storage/webstoragenamespace_impl.h"
-#include "content/renderer/fileapi/webfilesystem_impl.h"
 #include "content/renderer/image_capture/image_capture_frame_grabber.h"
 #include "content/renderer/indexed_db/webidbfactory_impl.h"
 #include "content/renderer/loader/child_url_loader_factory_bundle.h"
@@ -144,7 +142,6 @@
 using blink::WebBlobRegistry;
 using blink::WebCanvasCaptureHandler;
 using blink::WebDatabaseObserver;
-using blink::WebFileSystem;
 using blink::WebIDBFactory;
 using blink::WebImageCaptureFrameGrabber;
 using blink::WebMediaPlayer;
@@ -294,10 +291,11 @@
 
   GetInterfaceProvider()->GetInterface(
       mojo::MakeRequest(&web_database_host_info_));
+  GetInterfaceProvider()->GetInterface(
+      mojo::MakeRequest(&code_cache_host_info_));
 }
 
 RendererBlinkPlatformImpl::~RendererBlinkPlatformImpl() {
-  WebFileSystemImpl::DeleteThreadSpecificInstance();
   main_thread_scheduler_->SetTopLevelBlameContext(nullptr);
 }
 
@@ -463,22 +461,18 @@
   // browser may cache it and return it on subsequent responses to speed
   // the processing of this resource.
   std::vector<uint8_t> copy(data, data + size);
-  RenderThreadImpl::current()
-      ->render_message_filter()
-      ->DidGenerateCacheableMetadata(url, response_time, copy);
+  GetCodeCacheHost().DidGenerateCacheableMetadata(url, response_time, copy);
 }
 
 void RendererBlinkPlatformImpl::FetchCachedCode(
     const GURL& url,
     base::OnceCallback<void(base::Time, const std::vector<uint8_t>&)>
         callback) {
-  RenderThreadImpl::current()->render_message_filter()->FetchCachedCode(
-      url, std::move(callback));
+  GetCodeCacheHost().FetchCachedCode(url, std::move(callback));
 }
 
 void RendererBlinkPlatformImpl::ClearCodeCacheEntry(const GURL& url) {
-  RenderThreadImpl::current()->render_message_filter()->ClearCodeCacheEntry(
-      url);
+  GetCodeCacheHost().ClearCodeCacheEntry(url);
 }
 
 void RendererBlinkPlatformImpl::CacheMetadataInCacheStorage(
@@ -492,11 +486,9 @@
   // CacheStorage. The browser may cache it and return it on subsequent
   // responses to speed the processing of this resource.
   std::vector<uint8_t> copy(data, data + size);
-  RenderThreadImpl::current()
-      ->render_message_filter()
-      ->DidGenerateCacheableMetadataInCacheStorage(
-          url, response_time, copy, cacheStorageOrigin,
-          cacheStorageCacheName.Utf8());
+  GetCodeCacheHost().DidGenerateCacheableMetadataInCacheStorage(
+      url, response_time, copy, cacheStorageOrigin,
+      cacheStorageCacheName.Utf8());
 }
 
 WebString RendererBlinkPlatformImpl::DefaultLocale() {
@@ -582,10 +574,6 @@
 
 //------------------------------------------------------------------------------
 
-WebFileSystem* RendererBlinkPlatformImpl::FileSystem() {
-  return WebFileSystemImpl::ThreadSpecificInstance(default_task_runner_.get());
-}
-
 WebString RendererBlinkPlatformImpl::FileSystemCreateOriginIdentifier(
     const blink::WebSecurityOrigin& origin) {
   return WebString::FromUTF8(
@@ -1214,4 +1202,14 @@
   return **web_database_host_;
 }
 
+blink::mojom::CodeCacheHost& RendererBlinkPlatformImpl::GetCodeCacheHost() {
+  if (!code_cache_host_) {
+    code_cache_host_ = blink::mojom::ThreadSafeCodeCacheHostPtr::Create(
+        std::move(code_cache_host_info_),
+        base::CreateSequencedTaskRunnerWithTraits(
+            {base::WithBaseSyncPrimitives()}));
+  }
+  return **code_cache_host_;
+}
+
 }  // namespace content
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 5dd2ccd..02866eea 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -25,6 +25,7 @@
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/common/screen_orientation/web_screen_orientation_type.h"
+#include "third_party/blink/public/mojom/loader/code_cache.mojom.h"
 #include "third_party/blink/public/platform/modules/cache_storage/cache_storage.mojom.h"
 #include "third_party/blink/public/platform/modules/indexeddb/web_idb_factory.h"
 #include "third_party/blink/public/platform/modules/webdatabase/web_database.mojom.h"
@@ -124,7 +125,6 @@
   bool IsLockedToSite() const override;
 
   std::unique_ptr<blink::WebIDBFactory> CreateIdbFactory() override;
-  blink::WebFileSystem* FileSystem() override;
   blink::WebString FileSystemCreateOriginIdentifier(
       const blink::WebSecurityOrigin& origin) override;
 
@@ -223,6 +223,7 @@
   std::unique_ptr<blink::WebURLLoaderFactory> CreateDefaultURLLoaderFactory()
       override;
   std::unique_ptr<blink::CodeCacheLoader> CreateCodeCacheLoader() override;
+
   std::unique_ptr<blink::WebURLLoaderFactory> WrapURLLoaderFactory(
       mojo::ScopedMessagePipeHandle url_loader_factory_handle) override;
   std::unique_ptr<blink::WebURLLoaderFactory> WrapSharedURLLoaderFactory(
@@ -262,6 +263,9 @@
   // Return the mojo interface for making WebDatabaseHost calls.
   blink::mojom::WebDatabaseHost& GetWebDatabaseHost();
 
+  // Return the mojo interface for making CodeCache calls.
+  blink::mojom::CodeCacheHost& GetCodeCacheHost();
+
   blink::scheduler::WebThreadBase* compositor_thread_;
 
   std::unique_ptr<blink::WebThread> main_thread_;
@@ -301,6 +305,9 @@
   blink::mojom::WebDatabaseHostPtrInfo web_database_host_info_;
   scoped_refptr<blink::mojom::ThreadSafeWebDatabaseHostPtr> web_database_host_;
 
+  blink::mojom::CodeCacheHostPtrInfo code_cache_host_info_;
+  scoped_refptr<blink::mojom::ThreadSafeCodeCacheHostPtr> code_cache_host_;
+
 #if defined(OS_LINUX)
   sk_sp<font_service::FontLoader> font_loader_;
 #endif
diff --git a/content/renderer/skia_benchmarking_extension.cc b/content/renderer/skia_benchmarking_extension.cc
index 40200bb..ae5dd66b 100644
--- a/content/renderer/skia_benchmarking_extension.cc
+++ b/content/renderer/skia_benchmarking_extension.cc
@@ -285,9 +285,14 @@
   }
 
   v8::Local<v8::Object> result = v8::Object::New(isolate);
-  result->Set(v8::String::NewFromUtf8(isolate, "total_time"),
+  result->Set(v8::String::NewFromUtf8(isolate, "total_time",
+                                      v8::NewStringType::kInternalized)
+                  .ToLocalChecked(),
               v8::Number::New(isolate, total_time.InMillisecondsF()));
-  result->Set(v8::String::NewFromUtf8(isolate, "cmd_times"), op_times);
+  result->Set(v8::String::NewFromUtf8(isolate, "cmd_times",
+                                      v8::NewStringType::kInternalized)
+                  .ToLocalChecked(),
+              op_times);
 
   args->Return(result);
 }
@@ -303,9 +308,13 @@
     return;
 
   v8::Local<v8::Object> result = v8::Object::New(isolate);
-  result->Set(v8::String::NewFromUtf8(isolate, "width"),
+  result->Set(v8::String::NewFromUtf8(isolate, "width",
+                                      v8::NewStringType::kInternalized)
+                  .ToLocalChecked(),
               v8::Number::New(isolate, picture->layer_rect.width()));
-  result->Set(v8::String::NewFromUtf8(isolate, "height"),
+  result->Set(v8::String::NewFromUtf8(isolate, "height",
+                                      v8::NewStringType::kInternalized)
+                  .ToLocalChecked(),
               v8::Number::New(isolate, picture->layer_rect.height()));
 
   args->Return(result);
diff --git a/content/renderer/v8_value_converter_impl.cc b/content/renderer/v8_value_converter_impl.cc
index 13f3e8a4..1afe31ed3 100644
--- a/content/renderer/v8_value_converter_impl.cc
+++ b/content/renderer/v8_value_converter_impl.cc
@@ -258,8 +258,9 @@
     case base::Value::Type::STRING: {
       std::string val;
       CHECK(value->GetAsString(&val));
-      return v8::String::NewFromUtf8(
-          isolate, val.c_str(), v8::String::kNormalString, val.length());
+      return v8::String::NewFromUtf8(isolate, val.c_str(),
+                                     v8::NewStringType::kNormal, val.length())
+          .ToLocalChecked();
     }
 
     case base::Value::Type::LIST:
@@ -325,8 +326,9 @@
 
     v8::Maybe<bool> maybe = result->CreateDataProperty(
         context,
-        v8::String::NewFromUtf8(isolate, key.c_str(), v8::String::kNormalString,
-                                key.length()),
+        v8::String::NewFromUtf8(isolate, key.c_str(),
+                                v8::NewStringType::kNormal, key.length())
+            .ToLocalChecked(),
         child_v8);
     if (!maybe.IsJust() || !maybe.FromJust())
       LOG(ERROR) << "Failed to set property with key " << key;
diff --git a/content/shell/test_runner/gc_controller.cc b/content/shell/test_runner/gc_controller.cc
index 4ef63bd2..dd8a74a 100644
--- a/content/shell/test_runner/gc_controller.cc
+++ b/content/shell/test_runner/gc_controller.cc
@@ -63,11 +63,15 @@
 }
 
 void GCController::AsyncCollectAll(const gin::Arguments& args) {
-  if (args.PeekNext().IsEmpty()) {
-    NOTREACHED() << "AsyncCollectAll should be called with callback argument.";
+  v8::HandleScope scope(args.isolate());
+
+  if (args.PeekNext().IsEmpty() || !args.PeekNext()->IsFunction()) {
+    args.ThrowTypeError(
+        "asyncCollectAll should be called with a callback argument being a "
+        "v8::Function.");
+    return;
   }
 
-  v8::HandleScope scope(args.isolate());
   v8::UniquePersistent<v8::Function> func(
       args.isolate(), v8::Local<v8::Function>::Cast(args.PeekNext()));
 
diff --git a/content/test/data/accessibility/event/aria-combo-box-focus.html b/content/test/data/accessibility/event/aria-combo-box-focus.html
index 58eb56a..7f95c02 100644
--- a/content/test/data/accessibility/event/aria-combo-box-focus.html
+++ b/content/test/data/accessibility/event/aria-combo-box-focus.html
@@ -1,6 +1,7 @@
 <!--
 This line is to unflake the test, but may not be necessary (crbug.com/c/791268):
 @WIN-DENY:EVENT_OBJECT_LOCATIONCHANGE*
+@WIN-DENY:EVENT_OBJECT_SHOW*
 -->
 <!DOCTYPE html>
 <html>
diff --git a/content/test/data/accessibility/event/caret-move-expected-win.txt b/content/test/data/accessibility/event/caret-move-expected-win.txt
new file mode 100644
index 0000000..ce8ad57
--- /dev/null
+++ b/content/test/data/accessibility/event/caret-move-expected-win.txt
@@ -0,0 +1,8 @@
+EVENT_OBJECT_FOCUS on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
+EVENT_OBJECT_HIDE role=ROLE_SYSTEM_CARET INVISIBLE window_class=Chrome_WidgetWin_0
+EVENT_OBJECT_LOCATIONCHANGE role=ROLE_SYSTEM_CARET  window_class=Chrome_WidgetWin_0
+EVENT_OBJECT_LOCATIONCHANGE role=ROLE_SYSTEM_CARET  window_class=Chrome_WidgetWin_0
+EVENT_OBJECT_SHOW role=ROLE_SYSTEM_CARET  window_class=Chrome_WidgetWin_0
+EVENT_OBJECT_VALUECHANGE on <input#in1> role=ROLE_SYSTEM_TEXT value="end" FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
+IA2_EVENT_TEXT_CARET_MOVED on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
+IA2_EVENT_TEXT_CARET_MOVED on <input#in1> role=ROLE_SYSTEM_TEXT value="abcde" FOCUSED,FOCUSABLE IA2_STATE_EDITABLE,IA2_STATE_SELECTABLE_TEXT,IA2_STATE_SINGLE_LINE
diff --git a/content/test/data/accessibility/event/caret-move.html b/content/test/data/accessibility/event/caret-move.html
new file mode 100644
index 0000000..a4b641b
--- /dev/null
+++ b/content/test/data/accessibility/event/caret-move.html
@@ -0,0 +1,25 @@
+<!--
+@RUN-UNTIL-EVENT:EVENT_OBJECT_VALUECHANGE
+@WIN-DENY:IA2_EVENT_TEXT_INSERTED*
+@WIN-DENY:IA2_EVENT_TEXT_REMOVED*
+-->
+<!DOCTYPE html>
+<html>
+<body>
+<input id="in1" type="text" value="abcde">
+<script>
+  function go() {
+    const inp = document.getElementById('in1');
+    inp.focus();
+    inp.setSelectionRange(0, 0);
+    setTimeout(() => {
+      inp.setSelectionRange(1, 1);
+      setTimeout(() => {
+        inp.blur();
+        inp.value = 'end'; // Trigger test end.
+      }, 50);
+    }, 50);
+}
+</script>
+</body>
+</html>
\ No newline at end of file
diff --git a/content/test/data/accessibility/readme.md b/content/test/data/accessibility/readme.md
index 893dc47..05e1f46 100644
--- a/content/test/data/accessibility/readme.md
+++ b/content/test/data/accessibility/readme.md
@@ -85,8 +85,8 @@
 Normally the system waits for the document to finish loading before dumping
 the accessibility tree.
 
-Occasionally you may need to write a test that makes some changes to the
-document before it runs the test. In that case you can use a special
+Occasionally you may need to write a dump tree test that makes some changes to
+the document before it runs the test. In that case you can use a special
 @WAIT-FOR: directive. It should be in an HTML comment, just like
 @ALLOW-WIN: directives. The WAIT-FOR directive just specifies a text substring
 that should be present in the dump when the document is ready. The system
@@ -95,6 +95,16 @@
 You can add as many @WAIT-FOR: directives as you want, the test won't finish
 until all strings appear.
 
+Or, you may need to write an event test that keeps dumping events until a
+specific event line. In this case, use @RUN-UNTIL-EVENT with a substring that
+should occur in the event log, e.g. @RUN-UNTIL-EVENT:IA2_EVENT_TEXT_CARET_MOVED.
+Note that @RUN-UNTIL-EVENT is only used in dump events tests, and not used in
+dump tree tests.
+
+If you add multiple @RUN-UNTIL-EVENT directives, the test will finish once any
+of them are satisfied. Note that any other events that come along with the last
+event will also be logged.
+
 To skip dumping a particular element, make its accessible name equal to
 @NO_DUMP, for example <div aria-label="@NO_DUMP"></div>.
 
diff --git a/content/test/layouttest_support.cc b/content/test/layouttest_support.cc
index 5b5dc75b..abed7a9 100644
--- a/content/test/layouttest_support.cc
+++ b/content/test/layouttest_support.cc
@@ -237,9 +237,9 @@
 
 void EnableWebTestProxyCreation() {
   RenderViewImpl::InstallCreateHook(CreateWebViewTestProxy);
-  RenderWidget::InstallCreateHook(CreateWebWidgetTestProxy,
-                                  RenderWidgetInitialized);
-  RenderFrameImpl::InstallCreateHook(CreateWebFrameTestProxy);
+  RenderFrameImpl::InstallCreateHook(CreateWebFrameTestProxy,
+                                     CreateWebWidgetTestProxy,
+                                     RenderWidgetInitialized);
 }
 
 void FetchManifest(blink::WebView* view, FetchManifestCallback callback) {
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
index 0ce610e..5f04949 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.cc
@@ -677,18 +677,17 @@
 void WebRequestProxyingURLLoaderFactory::OnTargetFactoryError() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   target_factory_.reset();
-  if (proxy_bindings_.empty()) {
-    // Deletes |this|.
-    proxies_->RemoveProxy(this);
-  }
+  proxy_bindings_.CloseAllBindings();
+
+  MaybeRemoveProxy();
 }
 
 void WebRequestProxyingURLLoaderFactory::OnProxyBindingError() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-  if (proxy_bindings_.empty() && !target_factory_.is_bound()) {
-    // Deletes |this|.
-    proxies_->RemoveProxy(this);
-  }
+  if (proxy_bindings_.empty())
+    target_factory_.reset();
+
+  MaybeRemoveProxy();
 }
 
 void WebRequestProxyingURLLoaderFactory::RemoveRequest(
@@ -701,6 +700,18 @@
         this, content::GlobalRequestID(render_process_id_,
                                        network_service_request_id));
   }
+
+  MaybeRemoveProxy();
+}
+
+void WebRequestProxyingURLLoaderFactory::MaybeRemoveProxy() {
+  // Even if all URLLoaderFactory pipes connected to this object have been
+  // closed it has to stay alive until all active requests have completed.
+  if (target_factory_.is_bound() || !requests_.empty())
+    return;
+
+  // Deletes |this|.
+  proxies_->RemoveProxy(this);
 }
 
 }  // namespace extensions
diff --git a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
index 534b3e12..6be29d07 100644
--- a/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
+++ b/extensions/browser/api/web_request/web_request_proxying_url_loader_factory.h
@@ -193,6 +193,7 @@
   void OnTargetFactoryError();
   void OnProxyBindingError();
   void RemoveRequest(int32_t network_service_request_id, uint64_t request_id);
+  void MaybeRemoveProxy();
 
   void* const browser_context_;
   content::ResourceContext* const resource_context_;
diff --git a/extensions/browser/updater/update_service_unittest.cc b/extensions/browser/updater/update_service_unittest.cc
index 35b60939..5364e93 100644
--- a/extensions/browser/updater/update_service_unittest.cc
+++ b/extensions/browser/updater/update_service_unittest.cc
@@ -311,7 +311,7 @@
 
     scoped_refptr<Extension> extension1 =
         ExtensionBuilder("Foo")
-            .SetManifestKey("version", "1.0")
+            .SetVersion("1.0")
             .SetID(crx_file::id_util::GenerateId("foo_extension"))
             .SetPath(temp_dir.GetPath())
             .Build();
@@ -409,11 +409,11 @@
 
   // Build 3 extensions.
   scoped_refptr<Extension> extension1 =
-      ExtensionBuilder("1").SetManifestKey("version", "1.2").Build();
+      ExtensionBuilder("1").SetVersion("1.2").Build();
   scoped_refptr<Extension> extension2 =
-      ExtensionBuilder("2").SetManifestKey("version", "2.3").Build();
+      ExtensionBuilder("2").SetVersion("2.3").Build();
   scoped_refptr<Extension> extension3 =
-      ExtensionBuilder("3").SetManifestKey("version", "3.4").Build();
+      ExtensionBuilder("3").SetVersion("3.4").Build();
   EXPECT_TRUE(extension1->id() != extension2->id() &&
               extension1->id() != extension3->id() &&
               extension2->id() != extension3->id());
diff --git a/extensions/common/extension_builder.cc b/extensions/common/extension_builder.cc
index 48d256f..37b4de0 100644
--- a/extensions/common/extension_builder.cc
+++ b/extensions/common/extension_builder.cc
@@ -19,6 +19,7 @@
   std::vector<std::string> permissions;
   base::Optional<ActionType> action;
   base::Optional<BackgroundPage> background_page;
+  base::Optional<std::string> version;
 
   // A ContentScriptEntry includes a string name, and a vector of string
   // match patterns.
@@ -31,7 +32,7 @@
     DictionaryBuilder manifest;
     manifest.Set("name", name)
         .Set("manifest_version", 2)
-        .Set("version", "0.1")
+        .Set("version", version.value_or("0.1"))
         .Set("description", "some description");
 
     switch (type) {
@@ -185,6 +186,12 @@
   return *this;
 }
 
+ExtensionBuilder& ExtensionBuilder::SetVersion(const std::string& version) {
+  CHECK(manifest_data_);
+  manifest_data_->version = version;
+  return *this;
+}
+
 ExtensionBuilder& ExtensionBuilder::SetPath(const base::FilePath& path) {
   path_ = path;
   return *this;
diff --git a/extensions/common/extension_builder.h b/extensions/common/extension_builder.h
index c4af57e..3bd3544a 100644
--- a/extensions/common/extension_builder.h
+++ b/extensions/common/extension_builder.h
@@ -95,6 +95,11 @@
       const std::string& script_name,
       const std::vector<std::string>& match_patterns);
 
+  // Shortcut for setting a specific manifest version. Typically we'd use
+  // SetManifestKey() or SetManifestPath() for these, but provide a faster
+  // route for version, since it's so central.
+  ExtensionBuilder& SetVersion(const std::string& version);
+
   // Shortcuts to setting values on the manifest dictionary without needing to
   // go all the way through MergeManifest(). Sample usage:
   // ExtensionBuilder("name").SetManifestKey("version", "0.2").Build();
diff --git a/extensions/common/extension_builder_unittest.cc b/extensions/common/extension_builder_unittest.cc
index f446231..bb8bcac 100644
--- a/extensions/common/extension_builder_unittest.cc
+++ b/extensions/common/extension_builder_unittest.cc
@@ -224,4 +224,11 @@
   }
 }
 
+TEST(ExtensionBuilderTest, SetVersion) {
+  constexpr char kVersion[] = "42.0.99.1";
+  scoped_refptr<const Extension> extension =
+      ExtensionBuilder("foo").SetVersion(kVersion).Build();
+  EXPECT_EQ(kVersion, extension->VersionString());
+}
+
 }  // namespace extensions
diff --git a/extensions/renderer/activity_log_converter_strategy.cc b/extensions/renderer/activity_log_converter_strategy.cc
index 1663d15..d4612a4 100644
--- a/extensions/renderer/activity_log_converter_strategy.cc
+++ b/extensions/renderer/activity_log_converter_strategy.cc
@@ -22,25 +22,35 @@
   v8::TryCatch try_catch(isolate);
   v8::Isolate::DisallowJavascriptExecutionScope scope(
       isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
-  v8::Local<v8::String> name = v8::String::NewFromUtf8(isolate, "[");
+  v8::Local<v8::String> name =
+      v8::String::NewFromUtf8(isolate, "[", v8::NewStringType::kNormal)
+          .ToLocalChecked();
   if (object->IsFunction()) {
-    name = v8::String::Concat(isolate, name,
-                              v8::String::NewFromUtf8(isolate, "Function"));
+    name = v8::String::Concat(
+        isolate, name,
+        v8::String::NewFromUtf8(isolate, "Function", v8::NewStringType::kNormal)
+            .ToLocalChecked());
     v8::Local<v8::Value> fname =
         v8::Local<v8::Function>::Cast(object)->GetName();
     if (fname->IsString() && v8::Local<v8::String>::Cast(fname)->Length()) {
-      name = v8::String::Concat(isolate, name,
-                                v8::String::NewFromUtf8(isolate, " "));
+      name = v8::String::Concat(
+          isolate, name,
+          v8::String::NewFromUtf8(isolate, " ", v8::NewStringType::kNormal)
+              .ToLocalChecked());
       name =
           v8::String::Concat(isolate, name, v8::Local<v8::String>::Cast(fname));
-      name = v8::String::Concat(isolate, name,
-                                v8::String::NewFromUtf8(isolate, "()"));
+      name = v8::String::Concat(
+          isolate, name,
+          v8::String::NewFromUtf8(isolate, "()", v8::NewStringType::kNormal)
+              .ToLocalChecked());
     }
   } else {
     name = v8::String::Concat(isolate, name, object->GetConstructorName());
   }
-  name =
-      v8::String::Concat(isolate, name, v8::String::NewFromUtf8(isolate, "]"));
+  name = v8::String::Concat(
+      isolate, name,
+      v8::String::NewFromUtf8(isolate, "]", v8::NewStringType::kNormal)
+          .ToLocalChecked());
 
   if (try_catch.HasCaught()) {
     return std::unique_ptr<base::Value>(
diff --git a/extensions/renderer/blob_native_handler.cc b/extensions/renderer/blob_native_handler.cc
index 0a0e5e8..32fc9a6 100644
--- a/extensions/renderer/blob_native_handler.cc
+++ b/extensions/renderer/blob_native_handler.cc
@@ -15,8 +15,10 @@
 void GetBlobUuid(const v8::FunctionCallbackInfo<v8::Value>& args) {
   CHECK_EQ(1, args.Length());
   blink::WebBlob blob = blink::WebBlob::FromV8Value(args[0]);
-  args.GetReturnValue().Set(
-      v8::String::NewFromUtf8(args.GetIsolate(), blob.Uuid().Utf8().data()));
+  args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(),
+                                                    blob.Uuid().Utf8().data(),
+                                                    v8::NewStringType::kNormal)
+                                .ToLocalChecked());
 }
 
 }  // namespace
diff --git a/extensions/renderer/dispatcher.cc b/extensions/renderer/dispatcher.cc
index 60a59aac..875ff26 100644
--- a/extensions/renderer/dispatcher.cc
+++ b/extensions/renderer/dispatcher.cc
@@ -172,7 +172,9 @@
   void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) {
     // Check for the chrome property. If one doesn't exist, create one.
     v8::Local<v8::String> chrome_string(
-        v8::String::NewFromUtf8(context()->isolate(), "chrome"));
+        v8::String::NewFromUtf8(context()->isolate(), "chrome",
+                                v8::NewStringType::kInternalized)
+            .ToLocalChecked());
     v8::Local<v8::Object> global(context()->v8_context()->Global());
     v8::Local<v8::Value> chrome(global->Get(chrome_string));
     if (chrome->IsUndefined()) {
diff --git a/extensions/renderer/display_source_custom_bindings.cc b/extensions/renderer/display_source_custom_bindings.cc
index 4cea79d6..88f64ec 100644
--- a/extensions/renderer/display_source_custom_bindings.cc
+++ b/extensions/renderer/display_source_custom_bindings.cc
@@ -91,8 +91,10 @@
   CHECK(sink_id_val->IsInt32());
   const int sink_id = sink_id_val->ToInt32(isolate)->Value();
   if (GetDisplaySession(sink_id)) {
-    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
-        isolate, kSessionAlreadyStarted)));
+    isolate->ThrowException(v8::Exception::Error(
+        v8::String::NewFromUtf8(isolate, kSessionAlreadyStarted,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
 
@@ -104,7 +106,9 @@
   if ((video_stream_val->IsNull() || video_stream_val->IsUndefined()) &&
       (audio_stream_val->IsNull() || audio_stream_val->IsUndefined())) {
     isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+        v8::String::NewFromUtf8(isolate, kInvalidStreamArgs,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
 
@@ -116,7 +120,9 @@
                       .Component();
     if (video_track.IsNull()) {
       isolate->ThrowException(v8::Exception::Error(
-          v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+          v8::String::NewFromUtf8(isolate, kInvalidStreamArgs,
+                                  v8::NewStringType::kNormal)
+              .ToLocalChecked()));
       return;
     }
   }
@@ -126,7 +132,9 @@
                       .Component();
     if (audio_track.IsNull()) {
       isolate->ThrowException(v8::Exception::Error(
-          v8::String::NewFromUtf8(isolate, kInvalidStreamArgs)));
+          v8::String::NewFromUtf8(isolate, kInvalidStreamArgs,
+                                  v8::NewStringType::kNormal)
+              .ToLocalChecked()));
       return;
     }
   }
@@ -155,8 +163,10 @@
   std::unique_ptr<DisplaySourceSession> session =
       DisplaySourceSessionFactory::CreateSession(session_params);
   if (!session) {
-    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
-        isolate, kErrorNotSupported)));
+    isolate->ThrowException(v8::Exception::Error(
+        v8::String::NewFromUtf8(isolate, kErrorNotSupported,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
 
@@ -187,8 +197,10 @@
   int sink_id = args[0]->ToInt32(args.GetIsolate())->Value();
   DisplaySourceSession* session = GetDisplaySession(sink_id);
   if (!session) {
-    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
-        isolate, kSessionNotFound)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kSessionNotFound,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return;
   }
 
@@ -197,14 +209,18 @@
   if (state == DisplaySourceSession::Establishing) {
     // 'session started' callback has not yet been invoked.
     // This session is not existing for the user.
-    isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kSessionNotFound)));
+    isolate->ThrowException(
+        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kSessionNotFound,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()));
     return;
   }
 
   if (state == DisplaySourceSession::Terminating) {
-    isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(
-        isolate, kSessionAlreadyTerminating)));
+    isolate->ThrowException(v8::Exception::Error(
+        v8::String::NewFromUtf8(isolate, kSessionAlreadyTerminating,
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return;
   }
 
@@ -232,7 +248,9 @@
   if (success)
     callback_args[1] = v8::Null(isolate);
   else
-    callback_args[1] = v8::String::NewFromUtf8(isolate, error_message.c_str());
+    callback_args[1] = v8::String::NewFromUtf8(isolate, error_message.c_str(),
+                                               v8::NewStringType::kNormal)
+                           .ToLocalChecked();
 
   module_system->CallModuleMethodSafe("displaySource", "callCompletionCallback",
                                       2, callback_args);
diff --git a/extensions/renderer/file_system_natives.cc b/extensions/renderer/file_system_natives.cc
index f4a7cd8..1d906b6 100644
--- a/extensions/renderer/file_system_natives.cc
+++ b/extensions/renderer/file_system_natives.cc
@@ -120,7 +120,8 @@
 
   args.GetReturnValue().Set(
       v8::String::NewFromUtf8(isolate, filesystem_id.c_str(),
-                              v8::String::kNormalString, filesystem_id.size()));
+                              v8::NewStringType::kNormal, filesystem_id.size())
+          .ToLocalChecked());
 }
 
 }  // namespace extensions
diff --git a/extensions/renderer/i18n_custom_bindings.cc b/extensions/renderer/i18n_custom_bindings.cc
index 4a1b298..f43e993f 100644
--- a/extensions/renderer/i18n_custom_bindings.cc
+++ b/extensions/renderer/i18n_custom_bindings.cc
@@ -57,8 +57,11 @@
 
 void I18NCustomBindings::GetL10nUILanguage(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
-  args.GetReturnValue().Set(v8::String::NewFromUtf8(
-      args.GetIsolate(), content::RenderThread::Get()->GetLocale().c_str()));
+  args.GetReturnValue().Set(
+      v8::String::NewFromUtf8(args.GetIsolate(),
+                              content::RenderThread::Get()->GetLocale().c_str(),
+                              v8::NewStringType::kNormal)
+          .ToLocalChecked());
 }
 
 void I18NCustomBindings::DetectTextLanguage(
diff --git a/extensions/renderer/js_extension_bindings_system.cc b/extensions/renderer/js_extension_bindings_system.cc
index 1a6ff74f..783fa0c 100644
--- a/extensions/renderer/js_extension_bindings_system.cc
+++ b/extensions/renderer/js_extension_bindings_system.cc
@@ -37,7 +37,10 @@
 v8::Local<v8::Object> GetOrCreateObject(const v8::Local<v8::Object>& object,
                                         const std::string& field,
                                         v8::Isolate* isolate) {
-  v8::Local<v8::String> key = v8::String::NewFromUtf8(isolate, field.c_str());
+  v8::Local<v8::String> key =
+      v8::String::NewFromUtf8(isolate, field.c_str(),
+                              v8::NewStringType::kInternalized)
+          .ToLocalChecked();
   // If the object has a callback property, it is assumed it is an unavailable
   // API, so it is safe to delete. This is checked before GetOrCreateObject is
   // called.
@@ -60,7 +63,9 @@
 // an empty object.
 v8::Local<v8::Object> GetOrCreateChrome(ScriptContext* context) {
   v8::Local<v8::String> chrome_string(
-      v8::String::NewFromUtf8(context->isolate(), "chrome"));
+      v8::String::NewFromUtf8(context->isolate(), "chrome",
+                              v8::NewStringType::kInternalized)
+          .ToLocalChecked());
   v8::Local<v8::Object> global(context->v8_context()->Global());
   v8::Local<v8::Value> chrome(global->Get(chrome_string));
   if (chrome->IsUndefined()) {
@@ -280,7 +285,9 @@
     return;
 
   v8::Local<v8::String> v8_bind_name =
-      v8::String::NewFromUtf8(context->isolate(), bind_name.c_str());
+      v8::String::NewFromUtf8(context->isolate(), bind_name.c_str(),
+                              v8::NewStringType::kInternalized)
+          .ToLocalChecked();
   if (bind_object->HasRealNamedProperty(v8_bind_name)) {
     // The bind object may already have the property if the API has been
     // registered before (or if the extension has put something there already,
diff --git a/extensions/renderer/object_backed_native_handler.cc b/extensions/renderer/object_backed_native_handler.cc
index 7cd3ca6..9242b20 100644
--- a/extensions/renderer/object_backed_native_handler.cc
+++ b/extensions/renderer/object_backed_native_handler.cc
@@ -204,10 +204,13 @@
                                            v8::Local<v8::Object> obj,
                                            const char* key,
                                            v8::Local<v8::Value> value) {
-  obj->SetPrivate(context, v8::Private::ForApi(context->GetIsolate(),
-                                               v8::String::NewFromUtf8(
-                                                   context->GetIsolate(), key)),
-                  value)
+  obj->SetPrivate(
+         context,
+         v8::Private::ForApi(context->GetIsolate(),
+                             v8::String::NewFromUtf8(context->GetIsolate(), key,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()),
+         value)
       .FromJust();
 }
 
@@ -222,10 +225,12 @@
                                            v8::Local<v8::Object> obj,
                                            const char* key,
                                            v8::Local<v8::Value>* result) {
-  return obj->GetPrivate(context,
-                         v8::Private::ForApi(context->GetIsolate(),
-                                             v8::String::NewFromUtf8(
-                                                 context->GetIsolate(), key)))
+  return obj
+      ->GetPrivate(context, v8::Private::ForApi(context->GetIsolate(),
+                                                v8::String::NewFromUtf8(
+                                                    context->GetIsolate(), key,
+                                                    v8::NewStringType::kNormal)
+                                                    .ToLocalChecked()))
       .ToLocal(result);
 }
 
@@ -238,10 +243,12 @@
 void ObjectBackedNativeHandler::DeletePrivate(v8::Local<v8::Context> context,
                                               v8::Local<v8::Object> obj,
                                               const char* key) {
-  obj->DeletePrivate(context,
-                     v8::Private::ForApi(
-                         context->GetIsolate(),
-                         v8::String::NewFromUtf8(context->GetIsolate(), key)))
+  obj->DeletePrivate(
+         context,
+         v8::Private::ForApi(context->GetIsolate(),
+                             v8::String::NewFromUtf8(context->GetIsolate(), key,
+                                                     v8::NewStringType::kNormal)
+                                 .ToLocalChecked()))
       .FromJust();
 }
 
diff --git a/extensions/renderer/process_info_native_handler.cc b/extensions/renderer/process_info_native_handler.cc
index 7b3287d..224c9d48 100644
--- a/extensions/renderer/process_info_native_handler.cc
+++ b/extensions/renderer/process_info_native_handler.cc
@@ -61,14 +61,18 @@
 
 void ProcessInfoNativeHandler::GetExtensionId(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
-  args.GetReturnValue().Set(
-      v8::String::NewFromUtf8(args.GetIsolate(), extension_id_.c_str()));
+  args.GetReturnValue().Set(v8::String::NewFromUtf8(args.GetIsolate(),
+                                                    extension_id_.c_str(),
+                                                    v8::NewStringType::kNormal)
+                                .ToLocalChecked());
 }
 
 void ProcessInfoNativeHandler::GetContextType(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   args.GetReturnValue().Set(
-      v8::String::NewFromUtf8(args.GetIsolate(), context_type_.c_str()));
+      v8::String::NewFromUtf8(args.GetIsolate(), context_type_.c_str(),
+                              v8::NewStringType::kInternalized)
+          .ToLocalChecked());
 }
 
 void ProcessInfoNativeHandler::InIncognitoContext(
@@ -89,10 +93,13 @@
 void ProcessInfoNativeHandler::IsSendRequestDisabled(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   if (send_request_disabled_) {
-    args.GetReturnValue().Set(v8::String::NewFromUtf8(
-        args.GetIsolate(),
-        "sendRequest and onRequest are obsolete."
-        " Please use sendMessage and onMessage instead."));
+    args.GetReturnValue().Set(
+        v8::String::NewFromUtf8(
+            args.GetIsolate(),
+            "sendRequest and onRequest are obsolete."
+            " Please use sendMessage and onMessage instead.",
+            v8::NewStringType::kNormal)
+            .ToLocalChecked());
   }
 }
 
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc
index 329803a..69feec88 100644
--- a/extensions/renderer/script_context.cc
+++ b/extensions/renderer/script_context.cc
@@ -353,11 +353,15 @@
 
   v8::Local<v8::Value> argv[] = {
       v8::Integer::New(isolate(), request_id),
-      v8::String::NewFromUtf8(isolate(), name.c_str()),
+      v8::String::NewFromUtf8(isolate(), name.c_str(),
+                              v8::NewStringType::kNormal)
+          .ToLocalChecked(),
       v8::Boolean::New(isolate(), success),
       content::V8ValueConverter::Create()->ToV8Value(
           &response, v8::Local<v8::Context>::New(isolate(), v8_context_)),
-      v8::String::NewFromUtf8(isolate(), error.c_str())};
+      v8::String::NewFromUtf8(isolate(), error.c_str(),
+                              v8::NewStringType::kNormal)
+          .ToLocalChecked()};
 
   module_system()->CallModuleMethodSafe("sendRequest", "handleResponse",
                                         arraysize(argv), argv);
@@ -398,14 +402,18 @@
         "%s cannot be used within a sandboxed frame.";
     std::string error_msg = base::StringPrintf(kMessage, name.c_str());
     isolate()->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate(), error_msg.c_str())));
+        v8::String::NewFromUtf8(isolate(), error_msg.c_str(),
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return false;
   }
 
   Feature::Availability availability = GetAvailability(name);
   if (!availability.is_available()) {
     isolate()->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate(), availability.message().c_str())));
+        v8::String::NewFromUtf8(isolate(), availability.message().c_str(),
+                                v8::NewStringType::kNormal)
+            .ToLocalChecked()));
     return false;
   }
 
diff --git a/extensions/renderer/set_icon_natives.cc b/extensions/renderer/set_icon_natives.cc
index bc29330..45fd2f1 100644
--- a/extensions/renderer/set_icon_natives.cc
+++ b/extensions/renderer/set_icon_natives.cc
@@ -44,18 +44,30 @@
   v8::Local<v8::Context> v8_context = context()->v8_context();
   v8::Isolate* isolate = v8_context->GetIsolate();
   v8::Local<v8::Object> data =
-      image_data->Get(v8::String::NewFromUtf8(isolate, "data"))
+      image_data
+          ->Get(v8::String::NewFromUtf8(isolate, "data",
+                                        v8::NewStringType::kInternalized)
+                    .ToLocalChecked())
           ->ToObject(isolate);
-  int width = image_data->Get(v8::String::NewFromUtf8(isolate, "width"))
+  int width = image_data
+                  ->Get(v8::String::NewFromUtf8(
+                            isolate, "width", v8::NewStringType::kInternalized)
+                            .ToLocalChecked())
                   ->Int32Value(v8_context)
                   .FromMaybe(0);
-  int height = image_data->Get(v8::String::NewFromUtf8(isolate, "height"))
-                   ->Int32Value(v8_context)
-                   .FromMaybe(0);
+  int height =
+      image_data
+          ->Get(v8::String::NewFromUtf8(isolate, "height",
+                                        v8::NewStringType::kInternalized)
+                    .ToLocalChecked())
+          ->Int32Value(v8_context)
+          .FromMaybe(0);
 
   if (width <= 0 || height <= 0) {
     isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidDimensions)));
+        v8::String::NewFromUtf8(isolate, kInvalidDimensions,
+                                v8::NewStringType::kInternalized)
+            .ToLocalChecked()));
     return false;
   }
 
@@ -64,23 +76,32 @@
   int max_width = (std::numeric_limits<int>::max() / 4) / height;
   if (width > max_width) {
     isolate->ThrowException(v8::Exception::Error(
-        v8::String::NewFromUtf8(isolate, kInvalidDimensions)));
+        v8::String::NewFromUtf8(isolate, kInvalidDimensions,
+                                v8::NewStringType::kInternalized)
+            .ToLocalChecked()));
     return false;
   }
 
-  int data_length = data->Get(v8::String::NewFromUtf8(isolate, "length"))
-                        ->Int32Value(v8_context)
-                        .FromMaybe(0);
+  int data_length =
+      data->Get(v8::String::NewFromUtf8(isolate, "length",
+                                        v8::NewStringType::kInternalized)
+                    .ToLocalChecked())
+          ->Int32Value(v8_context)
+          .FromMaybe(0);
   if (data_length != 4 * width * height) {
-    isolate->ThrowException(
-        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidData)));
+    isolate->ThrowException(v8::Exception::Error(
+        v8::String::NewFromUtf8(isolate, kInvalidData,
+                                v8::NewStringType::kInternalized)
+            .ToLocalChecked()));
     return false;
   }
 
   SkBitmap bitmap;
   if (!bitmap.tryAllocN32Pixels(width, height)) {
-    isolate->ThrowException(
-        v8::Exception::Error(v8::String::NewFromUtf8(isolate, kNoMemory)));
+    isolate->ThrowException(v8::Exception::Error(
+        v8::String::NewFromUtf8(isolate, kNoMemory,
+                                v8::NewStringType::kInternalized)
+            .ToLocalChecked()));
     return false;
   }
   bitmap.eraseARGB(0, 0, 0, 0);
@@ -128,7 +149,10 @@
     v8::Local<v8::Object>* bitmap_set_value) {
   v8::Isolate* isolate = context()->v8_context()->GetIsolate();
   v8::Local<v8::Object> image_data_set =
-      details->Get(v8::String::NewFromUtf8(isolate, "imageData"))
+      details
+          ->Get(v8::String::NewFromUtf8(isolate, "imageData",
+                                        v8::NewStringType::kInternalized)
+                    .ToLocalChecked())
           ->ToObject(isolate);
 
   DCHECK(bitmap_set_value);
@@ -160,12 +184,16 @@
     return;
 
   v8::Local<v8::Object> dict(v8::Object::New(args.GetIsolate()));
-  dict->Set(v8::String::NewFromUtf8(args.GetIsolate(), "imageData"),
+  dict->Set(v8::String::NewFromUtf8(args.GetIsolate(), "imageData",
+                                    v8::NewStringType::kInternalized)
+                .ToLocalChecked(),
             bitmap_set_value);
-  if (details->Has(v8::String::NewFromUtf8(args.GetIsolate(), "tabId"))) {
-    dict->Set(
-        v8::String::NewFromUtf8(args.GetIsolate(), "tabId"),
-        details->Get(v8::String::NewFromUtf8(args.GetIsolate(), "tabId")));
+  v8::Local<v8::String> tabId =
+      v8::String::NewFromUtf8(args.GetIsolate(), "tabId",
+                              v8::NewStringType::kInternalized)
+          .ToLocalChecked();
+  if (details->Has(tabId)) {
+    dict->Set(tabId, details->Get(tabId));
   }
   args.GetReturnValue().Set(dict);
 }
diff --git a/extensions/renderer/v8_context_native_handler.cc b/extensions/renderer/v8_context_native_handler.cc
index 1ae5ef69..b7e6653c 100644
--- a/extensions/renderer/v8_context_native_handler.cc
+++ b/extensions/renderer/v8_context_native_handler.cc
@@ -35,11 +35,19 @@
   v8::Maybe<bool> maybe =
       ret->SetPrototype(context_->v8_context(), v8::Null(isolate));
   CHECK(maybe.IsJust() && maybe.FromJust());
-  ret->Set(v8::String::NewFromUtf8(isolate, "is_available"),
+  ret->Set(v8::String::NewFromUtf8(isolate, "is_available",
+                                   v8::NewStringType::kInternalized)
+               .ToLocalChecked(),
            v8::Boolean::New(isolate, availability.is_available()));
-  ret->Set(v8::String::NewFromUtf8(isolate, "message"),
-           v8::String::NewFromUtf8(isolate, availability.message().c_str()));
-  ret->Set(v8::String::NewFromUtf8(isolate, "result"),
+  ret->Set(v8::String::NewFromUtf8(isolate, "message",
+                                   v8::NewStringType::kInternalized)
+               .ToLocalChecked(),
+           v8::String::NewFromUtf8(isolate, availability.message().c_str(),
+                                   v8::NewStringType::kNormal)
+               .ToLocalChecked());
+  ret->Set(v8::String::NewFromUtf8(isolate, "result",
+                                   v8::NewStringType::kInternalized)
+               .ToLocalChecked(),
            v8::Integer::New(isolate, availability.result()));
   args.GetReturnValue().Set(ret);
 }
diff --git a/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc b/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc
index a0f169a..b77ad682 100644
--- a/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc
+++ b/extensions/shell/browser/system_logs/shell_system_logs_fetcher_unittest.cc
@@ -33,10 +33,7 @@
   scoped_refptr<Extension> BuildExtension(const std::string& name,
                                           const std::string& version,
                                           const std::string& id) {
-    return ExtensionBuilder(name)
-        .SetManifestKey("version", version)
-        .SetID(id)
-        .Build();
+    return ExtensionBuilder(name).SetVersion(version).SetID(id).Build();
   }
 
   void OnSystemLogsResponse(
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index fc6e9ebc..a4c6b245 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -214,7 +214,6 @@
     "//ios/chrome/browser/ui/first_run",
     "//ios/chrome/browser/ui/history",
     "//ios/chrome/browser/ui/main",
-    "//ios/chrome/browser/ui/main:feature_flags",
     "//ios/chrome/browser/ui/main:tab_switcher",
     "//ios/chrome/browser/ui/promos",
     "//ios/chrome/browser/ui/settings",
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 2ea71bd4..a9ad838 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -119,10 +119,8 @@
 #import "ios/chrome/browser/ui/first_run/first_run_util.h"
 #import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h"
 #include "ios/chrome/browser/ui/history/history_coordinator.h"
-#import "ios/chrome/browser/ui/history/history_panel_view_controller.h"
 #import "ios/chrome/browser/ui/main/browser_view_wrangler.h"
 #import "ios/chrome/browser/ui/main/main_coordinator.h"
-#import "ios/chrome/browser/ui/main/main_feature_flags.h"
 #import "ios/chrome/browser/ui/main/tab_switcher.h"
 #import "ios/chrome/browser/ui/main/view_controller_swapping.h"
 #import "ios/chrome/browser/ui/orientation_limiting_navigation_controller.h"
@@ -391,9 +389,6 @@
   // Cached launchOptions from -didFinishLaunchingWithOptions.
   NSDictionary* _launchOptions;
 
-  // View controller for displaying the legacy history panel.
-  UIViewController* _historyPanelViewController;
-
   // Coordinator for displaying history.
   HistoryCoordinator* _historyCoordinator;
 
@@ -1425,23 +1420,12 @@
 }
 
 - (void)showHistory {
-  if (IsUIRefreshPhase1Enabled()) {
-    // New History UIReboot coordinator.
-    _historyCoordinator = [[HistoryCoordinator alloc]
-        initWithBaseViewController:self.currentBVC
-                      browserState:_mainBrowserState];
-    _historyCoordinator.loader = self.currentBVC;
-    _historyCoordinator.dispatcher = self.mainBVC.dispatcher;
-    [_historyCoordinator start];
-  } else {
-    _historyPanelViewController = [[HistoryPanelViewController alloc]
-        initWithLoader:self.currentBVC
-          browserState:_mainBrowserState
-            dispatcher:self.mainBVC.dispatcher];
-    [self.currentBVC presentViewController:_historyPanelViewController
-                                  animated:YES
-                                completion:nil];
-  }
+  _historyCoordinator =
+      [[HistoryCoordinator alloc] initWithBaseViewController:self.currentBVC
+                                                browserState:_mainBrowserState];
+  _historyCoordinator.loader = self.currentBVC;
+  _historyCoordinator.dispatcher = self.mainBVC.dispatcher;
+  [_historyCoordinator start];
 }
 
 - (void)closeSettingsUIAndOpenURL:(OpenNewTabCommand*)command {
@@ -1476,18 +1460,6 @@
   }
 }
 
-- (void)showClearBrowsingDataSettingsFromViewController:
-    (UIViewController*)baseViewController {
-  if (_settingsNavigationController)
-    return;
-  _settingsNavigationController = [SettingsNavigationController
-      newClearBrowsingDataController:_mainBrowserState
-                            delegate:self];
-  [baseViewController presentViewController:_settingsNavigationController
-                                   animated:YES
-                                 completion:nil];
-}
-
 // TODO(crbug.com/779791) : Remove showing settings from MainController.
 - (void)showAutofillSettingsFromViewController:
     (UIViewController*)baseViewController {
@@ -1953,45 +1925,69 @@
           ->SetSnapshotCoalescingEnabled(false);
     }));
 
-    // Capture metrics on snapshotting.
-    ShowTabSwitcherSnapshotResult snapshotResult =
-        ShowTabSwitcherSnapshotResult::kSnapshotSucceeded;
-    if (currentTab.webState->IsLoading()) {
-      // Do not take a snapshot if the web state is loading, since it will be
-      // stale.
-      snapshotResult = ShowTabSwitcherSnapshotResult::
-          kSnapshotNotAttemptedBecausePageIsLoading;
-      SnapshotTabHelper::FromWebState(currentTab.webState)->RemoveSnapshot();
-      // TODO(crbug.com/869256) : It is possible that the navigation completes
-      // in the time it takes to animate to the tab grid. The navigation
-      // completion will trigger another snapshot. But that snapshot may have
-      // the previous webpage because the rendering is not guaranteed to have
-      // been completed at navigation completion. It is better to have a blank
-      // snapshot than the wrong snapshot. We pause snapshotting here, and
-      // resume once we have animated to the tab grid.
-      SnapshotTabHelper::FromWebState(currentTab.webState)->PauseSnapshotting();
-    } else {
-      // TODO(crbug.com/869256) : There is a very small possibility that the
-      // navigation has already completed, but the new webpage has not been
-      // rendered yet, so we may take a snapshot of the previous webpage. The
-      // reason for this is that rendering is not guaranteed at page loaded. But
-      // the possibility of this happening in this codepath is very small, and
-      // is not easily reproducible.
-      UIImage* snapshot = SnapshotTabHelper::FromWebState(currentTab.webState)
-                              ->UpdateSnapshot(/*with_overlays=*/true,
-                                               /*visible_frame_only=*/true);
-      // TODO(crbug.com/711455) : Snapshot generation can fail for certain
-      // websites that have video somewhere on the page. If the snapshot
-      // generation fails, the stale snapshot should be removed so as not to
-      // display an old snapshot.
-      if (snapshot == SnapshotTabHelper::GetDefaultSnapshotImage()) {
-        snapshotResult =
-            ShowTabSwitcherSnapshotResult::kSnapshotAttemptedAndFailed;
-        SnapshotTabHelper::FromWebState(currentTab.webState)->RemoveSnapshot();
+    if (IsWKWebViewSnapshotsEnabled()) {
+      if (currentTab.webState->IsLoading()) {
+        UMA_HISTOGRAM_ENUMERATION(
+            "IOS.ShowTabSwitcherSnapshotResult",
+            ShowTabSwitcherSnapshotResult::
+                kSnapshotNotAttemptedBecausePageIsLoading);
+      } else {
+        SnapshotTabHelper::FromWebState(currentTab.webState)
+            ->UpdateSnapshotWithCallback(^(UIImage* snapshot) {
+              if (snapshot == SnapshotTabHelper::GetDefaultSnapshotImage()) {
+                UMA_HISTOGRAM_ENUMERATION(
+                    "IOS.ShowTabSwitcherSnapshotResult",
+                    ShowTabSwitcherSnapshotResult::kSnapshotAttemptedAndFailed);
+              } else {
+                UMA_HISTOGRAM_ENUMERATION(
+                    "IOS.ShowTabSwitcherSnapshotResult",
+                    ShowTabSwitcherSnapshotResult::kSnapshotSucceeded);
+              }
+            });
       }
+    } else {
+      // Capture metrics on snapshotting.
+      ShowTabSwitcherSnapshotResult snapshotResult =
+          ShowTabSwitcherSnapshotResult::kSnapshotSucceeded;
+      if (currentTab.webState->IsLoading()) {
+        // Do not take a snapshot if the web state is loading, since it will be
+        // stale.
+        snapshotResult = ShowTabSwitcherSnapshotResult::
+            kSnapshotNotAttemptedBecausePageIsLoading;
+        SnapshotTabHelper::FromWebState(currentTab.webState)->RemoveSnapshot();
+        // TODO(crbug.com/869256) : It is possible that the navigation completes
+        // in the time it takes to animate to the tab grid. The navigation
+        // completion will trigger another snapshot. But that snapshot may have
+        // the previous webpage because the rendering is not guaranteed to have
+        // been completed at navigation completion. It is better to have a blank
+        // snapshot than the wrong snapshot. We pause snapshotting here, and
+        // resume once we have animated to the tab grid.
+        SnapshotTabHelper::FromWebState(currentTab.webState)
+            ->PauseSnapshotting();
+      } else {
+        // TODO(crbug.com/869256) : There is a very small possibility that the
+        // navigation has already completed, but the new webpage has not been
+        // rendered yet, so we may take a snapshot of the previous webpage. The
+        // reason for this is that rendering is not guaranteed at page loaded.
+        // But the possibility of this happening in this codepath is very small,
+        // and is not easily reproducible.
+        UIImage* snapshot = SnapshotTabHelper::FromWebState(currentTab.webState)
+                                ->UpdateSnapshot(/*with_overlays=*/true,
+                                                 /*visible_frame_only=*/true);
+        // TODO(crbug.com/711455) : Snapshot generation can fail for certain
+        // websites that have video somewhere on the page. If the snapshot
+        // generation fails, the stale snapshot should be removed so as not to
+        // display an old snapshot.
+        if (snapshot == SnapshotTabHelper::GetDefaultSnapshotImage()) {
+          snapshotResult =
+              ShowTabSwitcherSnapshotResult::kSnapshotAttemptedAndFailed;
+          SnapshotTabHelper::FromWebState(currentTab.webState)
+              ->RemoveSnapshot();
+        }
+      }
+      UMA_HISTOGRAM_ENUMERATION("IOS.ShowTabSwitcherSnapshotResult",
+                                snapshotResult);
     }
-    UMA_HISTOGRAM_ENUMERATION("IOS.ShowTabSwitcherSnapshotResult",
-                              snapshotResult);
   }
 
   DCHECK(_tabSwitcher);
@@ -2103,30 +2099,15 @@
   self.currentBVC = targetBVC;
 
   // The call to set currentBVC above does not actually display the BVC, because
-  // _dismissingTabSwitcher is YES.  When the presentation experiment is
-  // enabled, force the BVC transition to start.
-  if (TabSwitcherPresentsBVCEnabled()) {
-    [self displayCurrentBVCAndFocusOmnibox:focusOmnibox];
-  }
+  // _dismissingTabSwitcher is YES.  So: Force the BVC transition to start.
+  [self displayCurrentBVCAndFocusOmnibox:focusOmnibox];
 }
 
 - (void)finishDismissingTabSwitcher {
-  // The tab switcher presentation experiment modifies the app's VC hierarchy.
-  // As a result, the "active" VC when the animation completes differs based on
-  // the experiment state.
-  if (TabSwitcherPresentsBVCEnabled()) {
-    // When the experiment is enabled, the tab switcher dismissal animation runs
-    // as part of the BVC presentation process.  The BVC is presented before the
-    // animations begin, so it is the current active VC at this point.
-    DCHECK_EQ(self.viewControllerSwapper.activeViewController, self.currentBVC);
-  } else {
-    // Without the experiment, the BVC is added as a child and made visible in
-    // the call to |displayCurrentBVC| below, after the tab switcher dismissal
-    // animation is complete.  At this point in the process, the tab switcher is
-    // still the active VC.
-    DCHECK_EQ(self.viewControllerSwapper.activeViewController,
-              [_tabSwitcher viewController]);
-  }
+  // The tab switcher dismissal animation runs
+  // as part of the BVC presentation process.  The BVC is presented before the
+  // animations begin, so it should be the current active VC at this point.
+  DCHECK_EQ(self.viewControllerSwapper.activeViewController, self.currentBVC);
 
   if (_modeToDisplayOnTabSwitcherDismissal ==
       TabSwitcherDismissalMode::NORMAL) {
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index d245b44..ca998b9 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -132,8 +132,6 @@
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/external_search:feature_flags",
     "//ios/chrome/browser/ui/fullscreen:feature_flags",
-    "//ios/chrome/browser/ui/history:feature_flags",
-    "//ios/chrome/browser/ui/main:feature_flags",
     "//ios/chrome/browser/ui/omnibox",
     "//ios/chrome/browser/ui/toolbar/public:feature_flags",
     "//ios/chrome/browser/ui/toolbar_container:feature_flags",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index b8241082..57fddf5 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -36,6 +36,7 @@
 #include "components/payments/core/features.h"
 #include "components/search_provider_logos/switches.h"
 #include "components/security_state/core/features.h"
+#include "components/signin/core/browser/account_reconcilor.h"
 #include "components/signin/core/browser/signin_switches.h"
 #include "components/strings/grit/components_strings.h"
 #include "components/sync/driver/sync_driver_switches.h"
@@ -52,8 +53,6 @@
 #include "ios/chrome/browser/ssl/captive_portal_features.h"
 #include "ios/chrome/browser/ui/external_search/features.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
-#import "ios/chrome/browser/ui/history/features.h"
-#include "ios/chrome/browser/ui/main/main_feature_flags.h"
 #import "ios/chrome/browser/ui/toolbar/public/features.h"
 #import "ios/chrome/browser/ui/toolbar_container/toolbar_container_features.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
@@ -189,17 +188,9 @@
     {"drag_and_drop", flag_descriptions::kDragAndDropName,
      flag_descriptions::kDragAndDropDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kDragAndDrop)},
-    {"tab_switcher_presents_bvc",
-     flag_descriptions::kTabSwitcherPresentsBVCName,
-     flag_descriptions::kTabSwitcherPresentsBVCDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kTabSwitcherPresentsBVC)},
     {"external-search", flag_descriptions::kExternalSearchName,
      flag_descriptions::kExternalSearchDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kExternalSearch)},
-    {"history-batch-updates-filter",
-     flag_descriptions::kHistoryBatchUpdatesFilterName,
-     flag_descriptions::kHistoryBatchUpdatesFilterDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(kHistoryBatchUpdatesFilter)},
     {"slim-navigation-manager", flag_descriptions::kSlimNavigationManagerName,
      flag_descriptions::kSlimNavigationManagerDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(web::features::kSlimNavigationManager)},
@@ -395,6 +386,9 @@
     {"custom-search-engines", flag_descriptions::kCustomSearchEnginesName,
      flag_descriptions::kCustomSearchEnginesDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kCustomSearchEngines)},
+    {"use-multilogin-endpoint", flag_descriptions::kUseMultiloginEndpointName,
+     flag_descriptions::kUseMultiloginEndpointDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(kUseMultiloginEndpoint)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/autofill/automation/automation_action.mm b/ios/chrome/browser/autofill/automation/automation_action.mm
index 3b35cff..a9bdcfa 100644
--- a/ios/chrome/browser/autofill/automation/automation_action.mm
+++ b/ios/chrome/browser/autofill/automation/automation_action.mm
@@ -249,11 +249,23 @@
 
 @implementation AutomationActionAutofill
 
-static const char PROFILE_NAME_FULL[] = "Yuki Nagato";
-static const char PROFILE_HOME_LINE1[] = "1600 Amphitheatre Parkway";
-static const char PROFILE_HOME_CITY[] = "Mountain View";
-static const char PROFILE_HOME_STATE[] = "CA";
-static const char PROFILE_HOME_ZIP[] = "94043";
+static const char PROFILE_NAME_FULL[] = "Milton C. Waddams";
+static const char PROFILE_NAME_FIRST[] = "Milton";
+static const char PROFILE_NAME_MIDDLE[] = "C.";
+static const char PROFILE_NAME_LAST[] = "Waddams";
+static const char PROFILE_HOME_LINE1[] = "4120 Freidrich Lane";
+static const char PROFILE_HOME_LINE2[] = "Apt 8";
+static const char PROFILE_HOME_CITY[] = "Austin";
+static const char PROFILE_HOME_STATE[] = "Texas";
+static const char PROFILE_COMPANY_NAME[] = "Initech";
+static const char PROFILE_EMAIL_ADDRESS[] = "red.swingline@initech.com";
+static const char PROFILE_HOME_ZIP[] = "78744";
+static const char PROFILE_PHONE_HOME_CITY_CODE[] = "512";
+static const char PROFILE_PHONE_HOME_WHOLE[] = "5125551234";
+static const char PROFILE_CREDIT_CARD_NUMBER[] = "9621327911759602";
+static const char PROFILE_CREDIT_CARD_NAME_FULL[] = "Milton Waddams";
+static const char PROFILE_CREDIT_CARD_EXP_MONTH[] = "5";
+static const char PROFILE_CREDIT_CARD_EXP_4_DIGIT_YEAR[] = "2027";
 
 // Loads the predefined autofill profile into the personal data manager, so that
 // autofill actions will be suggested when tapping on an autofillable form.
@@ -268,15 +280,43 @@
   autofill::AutofillProfile profile(base::GenerateGUID(),
                                     "https://www.example.com/");
   profile.SetRawInfo(autofill::NAME_FULL, base::UTF8ToUTF16(PROFILE_NAME_FULL));
+  profile.SetRawInfo(autofill::NAME_FIRST,
+                     base::UTF8ToUTF16(PROFILE_NAME_FIRST));
+  profile.SetRawInfo(autofill::NAME_MIDDLE,
+                     base::UTF8ToUTF16(PROFILE_NAME_MIDDLE));
+  profile.SetRawInfo(autofill::NAME_LAST, base::UTF8ToUTF16(PROFILE_NAME_LAST));
   profile.SetRawInfo(autofill::ADDRESS_HOME_LINE1,
                      base::UTF8ToUTF16(PROFILE_HOME_LINE1));
+  profile.SetRawInfo(autofill::ADDRESS_HOME_LINE2,
+                     base::UTF8ToUTF16(PROFILE_HOME_LINE2));
   profile.SetRawInfo(autofill::ADDRESS_HOME_CITY,
                      base::UTF8ToUTF16(PROFILE_HOME_CITY));
   profile.SetRawInfo(autofill::ADDRESS_HOME_STATE,
                      base::UTF8ToUTF16(PROFILE_HOME_STATE));
+  profile.SetRawInfo(autofill::COMPANY_NAME,
+                     base::UTF8ToUTF16(PROFILE_COMPANY_NAME));
+  profile.SetRawInfo(autofill::EMAIL_ADDRESS,
+                     base::UTF8ToUTF16(PROFILE_EMAIL_ADDRESS));
   profile.SetRawInfo(autofill::ADDRESS_HOME_ZIP,
                      base::UTF8ToUTF16(PROFILE_HOME_ZIP));
+  profile.SetRawInfo(autofill::PHONE_HOME_CITY_CODE,
+                     base::UTF8ToUTF16(PROFILE_PHONE_HOME_CITY_CODE));
+  profile.SetRawInfo(autofill::PHONE_HOME_WHOLE_NUMBER,
+                     base::UTF8ToUTF16(PROFILE_PHONE_HOME_WHOLE));
   personal_data_manager->SaveImportedProfile(profile);
+
+  autofill::CreditCard credit_card(base::GenerateGUID(),
+                                   "https://www.example.com/");
+  credit_card.SetRawInfo(autofill::CREDIT_CARD_NUMBER,
+                         base::UTF8ToUTF16(PROFILE_CREDIT_CARD_NUMBER));
+  credit_card.SetRawInfo(autofill::CREDIT_CARD_NAME_FULL,
+                         base::UTF8ToUTF16(PROFILE_CREDIT_CARD_NAME_FULL));
+  credit_card.SetRawInfo(autofill::CREDIT_CARD_EXP_MONTH,
+                         base::UTF8ToUTF16(PROFILE_CREDIT_CARD_EXP_MONTH));
+  credit_card.SetRawInfo(
+      autofill::CREDIT_CARD_EXP_4_DIGIT_YEAR,
+      base::UTF8ToUTF16(PROFILE_CREDIT_CARD_EXP_4_DIGIT_YEAR));
+  personal_data_manager->AddCreditCard(credit_card);
 }
 
 - (void)execute {
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index d094f76..fa622a8a 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -250,12 +250,6 @@
 const char kSSOWithWKWebViewDescription[] =
     "Using WKWebView instead of UIWebView in SSO";
 
-const char kTabSwitcherPresentsBVCName[] = "TabSwitcher Presents BVC";
-const char kTabSwitcherPresentsBVCDescription[] =
-    "When enabled, the tab switcher will present the BVC, so that when the "
-    "BVC is visible, the tab switcher will remain in the VC hierarchy "
-    "underneath it.";
-
 const char kToolbarContainerName[] = "Use Toolbar Containers";
 const char kToolbarContainerDescription[] =
     "When enabled, the toolbars and their fullscreen animations will be "
@@ -267,6 +261,10 @@
     "features. This includes new confirmation screens and improved settings "
     "pages.";
 
+const char kUseMultiloginEndpointName[] = "Use Multilogin endpoint.";
+const char kUseMultiloginEndpointDescription[] =
+    "Use Gaia OAuth multilogin for identity consistency.";
+
 const char kForceUnifiedConsentBumpName[] = "Force Unified Consent Bump";
 const char kForceUnifiedConsentBumpDescription[] =
     "Force the unified consent bump UI to be shown on every start-up. This "
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index a9803ee..6efd1f8 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -207,11 +207,6 @@
 extern const char kSSOWithWKWebViewName[];
 extern const char kSSOWithWKWebViewDescription[];
 
-// Title and description for the flag to enable the TabSwitcher to present the
-// BVC.
-extern const char kTabSwitcherPresentsBVCName[];
-extern const char kTabSwitcherPresentsBVCDescription[];
-
 // Title and description for the flag to enable the toolbar container
 // implementation.
 extern const char kToolbarContainerName[];
@@ -221,6 +216,11 @@
 extern const char kUnifiedConsentName[];
 extern const char kUnifiedConsentDescription[];
 
+// Title and description for the flag to enable Gaia Auth Mutlilogin endpoint
+// for identity consistency.
+extern const char kUseMultiloginEndpointName[];
+extern const char kUseMultiloginEndpointDescription[];
+
 // Title and description for the flag to force the consent bump.
 extern const char kForceUnifiedConsentBumpName[];
 extern const char kForceUnifiedConsentBumpDescription[];
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc b/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc
index fbbf586d..af1b2ce7 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc
+++ b/ios/chrome/browser/passwords/ios_chrome_password_store_factory.cc
@@ -99,7 +99,7 @@
     LOG(WARNING) << "Could not initialize password store.";
     return nullptr;
   }
-  password_manager_util::DeleteBlacklistedDuplicates(
+  password_manager_util::RemoveUselessCredentials(
       store, ios::ChromeBrowserState::FromBrowserState(context)->GetPrefs(),
       60);
   return store;
diff --git a/ios/chrome/browser/prefs/BUILD.gn b/ios/chrome/browser/prefs/BUILD.gn
index e3e3a6b..9f414ac 100644
--- a/ios/chrome/browser/prefs/BUILD.gn
+++ b/ios/chrome/browser/prefs/BUILD.gn
@@ -53,6 +53,7 @@
     "//components/signin/core/browser",
     "//components/strings",
     "//components/sync",
+    "//components/sync_sessions",
     "//components/translate/core/browser",
     "//components/translate/core/common",
     "//components/unified_consent",
diff --git a/ios/chrome/browser/prefs/browser_prefs.mm b/ios/chrome/browser/prefs/browser_prefs.mm
index a23789d3..f1a0702 100644
--- a/ios/chrome/browser/prefs/browser_prefs.mm
+++ b/ios/chrome/browser/prefs/browser_prefs.mm
@@ -34,6 +34,7 @@
 #include "components/signin/core/browser/signin_pref_names.h"
 #include "components/strings/grit/components_locale_settings.h"
 #include "components/sync/base/sync_prefs.h"
+#include "components/sync_sessions/session_sync_prefs.h"
 #include "components/translate/core/browser/translate_pref_names.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/unified_consent/unified_consent_service.h"
@@ -116,6 +117,7 @@
   payments::RegisterProfilePrefs(registry);
   PrefProxyConfigTrackerImpl::RegisterProfilePrefs(registry);
   RegisterVoiceSearchBrowserStatePrefs(registry);
+  sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(registry);
   syncer::SyncPrefs::RegisterProfilePrefs(registry);
   TemplateURLPrepopulateData::RegisterProfilePrefs(registry);
   translate::TranslatePrefs::RegisterProfilePrefs(registry);
diff --git a/ios/chrome/browser/snapshots/BUILD.gn b/ios/chrome/browser/snapshots/BUILD.gn
index 3026311..3cab42f 100644
--- a/ios/chrome/browser/snapshots/BUILD.gn
+++ b/ios/chrome/browser/snapshots/BUILD.gn
@@ -41,6 +41,7 @@
     "//ios/chrome/browser/web:tab_id_tab_helper",
     "//ios/chrome/browser/web_state_list",
     "//ios/web/public",
+    "//ui/gfx",
   ]
   libs = [
     "QuartzCore.framework",
diff --git a/ios/chrome/browser/snapshots/snapshot_generator.h b/ios/chrome/browser/snapshots/snapshot_generator.h
index 2e7fc84d..b2e01f6c 100644
--- a/ios/chrome/browser/snapshots/snapshot_generator.h
+++ b/ios/chrome/browser/snapshots/snapshot_generator.h
@@ -47,16 +47,20 @@
 - (void)retrieveGreySnapshot:(void (^)(UIImage*))callback;
 
 // Invalidates the cached snapshot for the current page, generates and caches
-// a new snapshot. Returns the snapshot with or without the overlayed views
-// (e.g. infobar, voice search button, etc.), and either of the visible frame
-// or of the full screen.
+// a new snapshot. Returns the snapshot with or without the overlaid views
+// (e.g. infobar), and either of the visible frame or of the full screen.
 - (UIImage*)updateSnapshotWithOverlays:(BOOL)shouldAddOverlay
                       visibleFrameOnly:(BOOL)visibleFrameOnly;
 
+// Invalidates the cached snapshot for the current page, generates and caches
+// a new snapshot. Calls |completion| with a snapshot with overlaid views (e.g.
+// infobar) of the visible frame. This method should only be called if the web
+// state has a valid web view.
+- (void)updateWebViewSnapshotWithCompletion:(void (^)(UIImage*))completion;
+
 // Generates a new snapshot for the current page including optional infobars.
-// Returns the snapshot with or without the overlayed views (e.g. infobar,
-// voice search button, etc.), and either of the visible frame or of the full
-// screen.
+// Returns the snapshot with or without the overlaid views (e.g. infobar), and
+// either of the visible frame or of the full screen.
 - (UIImage*)generateSnapshotWithOverlays:(BOOL)shouldAddOverlay
                         visibleFrameOnly:(BOOL)visibleFrameOnly;
 
diff --git a/ios/chrome/browser/snapshots/snapshot_generator.mm b/ios/chrome/browser/snapshots/snapshot_generator.mm
index 5e450a22..a12504d 100644
--- a/ios/chrome/browser/snapshots/snapshot_generator.mm
+++ b/ios/chrome/browser/snapshots/snapshot_generator.mm
@@ -22,6 +22,7 @@
 #import "ios/web/public/features.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
+#include "ui/gfx/image/image.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -102,6 +103,12 @@
                            withRect:(CGRect)rect
                            overlays:(NSArray<SnapshotOverlay*>*)overlays;
 
+// Returns an image of the |snapshot| overlaid with |overlays| with the given
+// |frame|.
+- (UIImage*)snapshotWithOverlays:(NSArray<SnapshotOverlay*>*)overlays
+                        snapshot:(UIImage*)snapshot
+                           frame:(CGRect)frame;
+
 // Property providing access to the snapshot's cache. May be nil.
 @property(nonatomic, readonly) SnapshotCache* snapshotCache;
 
@@ -206,6 +213,45 @@
   return snapshot;
 }
 
+- (void)updateWebViewSnapshotWithCompletion:(void (^)(UIImage*))completion {
+  DCHECK(_webState);
+  CGRect frame = [self snapshotFrameVisibleFrameOnly:YES];
+  if (CGRectIsEmpty(frame))
+    return;
+  NSArray<SnapshotOverlay*>* overlays =
+      [_delegate snapshotOverlaysForWebState:_webState];
+  UIImage* snapshot =
+      [_coalescingSnapshotContext cachedSnapshotWithOverlays:overlays
+                                            visibleFrameOnly:YES];
+  if (snapshot) {
+    if (completion)
+      completion(snapshot);
+    return;
+  }
+
+  [_delegate willUpdateSnapshotForWebState:_webState];
+  __weak SnapshotGenerator* weakSelf = self;
+  _webState->TakeSnapshot(base::BindOnce(^(gfx::Image image) {
+    SnapshotGenerator* strongSelf = weakSelf;
+    if (!strongSelf)
+      return;
+    UIImage* snapshot = image.ToUIImage();
+    if (overlays.count > 0) {
+      snapshot = [strongSelf snapshotWithOverlays:overlays
+                                         snapshot:snapshot
+                                            frame:frame];
+    }
+    [strongSelf.snapshotCache setImage:snapshot
+                         withSessionID:_snapshotSessionId];
+    [_coalescingSnapshotContext setCachedSnapshot:snapshot
+                                     withOverlays:overlays
+                                 visibleFrameOnly:YES];
+    [_delegate didUpdateSnapshotForWebState:_webState withImage:snapshot];
+    if (completion)
+      completion(snapshot);
+  }));
+}
+
 - (UIImage*)generateSnapshotWithOverlays:(BOOL)shouldAddOverlay
                         visibleFrameOnly:(BOOL)visibleFrameOnly {
   CGRect frame = [self snapshotFrameVisibleFrameOnly:visibleFrameOnly];
@@ -351,6 +397,37 @@
   return image;
 }
 
+- (UIImage*)snapshotWithOverlays:(NSArray<SnapshotOverlay*>*)overlays
+                        snapshot:(UIImage*)snapshot
+                           frame:(CGRect)frame {
+  CGSize size = frame.size;
+  DCHECK(std::isnormal(size.width) && (size.width > 0))
+      << ": size.width=" << size.width;
+  DCHECK(std::isnormal(size.height) && (size.height > 0))
+      << ": size.height=" << size.height;
+  const CGFloat kScale =
+      std::max<CGFloat>(1.0, [self.snapshotCache snapshotScaleForDevice]);
+  UIGraphicsBeginImageContextWithOptions(size, YES, kScale);
+  CGContext* context = UIGraphicsGetCurrentContext();
+  DCHECK(context);
+  CGContextSaveGState(context);
+  [snapshot drawAtPoint:CGPointZero];
+  for (SnapshotOverlay* overlay in overlays) {
+    // Render the overlay view at the desired offset. It is achieved
+    // by shifting origin of context because view frame is ignored when
+    // drawing to context.
+    CGContextSaveGState(context);
+    CGContextTranslateCTM(context, 0, overlay.yOffset - frame.origin.y);
+    [overlay.view drawViewHierarchyInRect:overlay.view.bounds
+                       afterScreenUpdates:YES];
+    CGContextRestoreGState(context);
+  }
+  UIImage* snapshotWithOverlays = UIGraphicsGetImageFromCurrentImageContext();
+  CGContextRestoreGState(context);
+  UIGraphicsEndImageContext();
+  return snapshotWithOverlays;
+}
+
 #pragma mark - Properties.
 
 - (SnapshotCache*)snapshotCache {
diff --git a/ios/chrome/browser/snapshots/snapshot_tab_helper.h b/ios/chrome/browser/snapshots/snapshot_tab_helper.h
index 44f507d..3a43b15 100644
--- a/ios/chrome/browser/snapshots/snapshot_tab_helper.h
+++ b/ios/chrome/browser/snapshots/snapshot_tab_helper.h
@@ -10,6 +10,7 @@
 #import <UIKit/UIKit.h>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "components/infobars/core/infobar_manager.h"
 #import "ios/web/public/web_state/web_state_observer.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
@@ -50,14 +51,20 @@
   void RetrieveGreySnapshot(void (^callback)(UIImage*));
 
   // Invalidates the cached snapshot for the current page and forces the
+  // generation of a more recent snapshot. Runs |callback| with a snapshot with
+  // overlaid views (e.g. infobar) of the visible frame. In iOS 11+, snapshots
+  // of a valid web view are taken using WKWebView's snapshotting API.
+  void UpdateSnapshotWithCallback(void (^callback)(UIImage*));
+
+  // Invalidates the cached snapshot for the current page and forces the
   // generation of a more recent snapshot. Returns the snapshot with or
-  // without the overlayed views (e.g. infobar, voice search button, ...)
-  // and either of the visible frame or of the full screen.
+  // without the overlaid views (e.g. infobar) and either of the visible frame
+  // or of the full screen.
   UIImage* UpdateSnapshot(bool with_overlays, bool visible_frame_only);
 
   // Generates a snapshot for the current page. Returns the snapshot with
-  // or without the overlayed views (e.g. infobar, voice search button, ...)
-  // and either of the visible frame of of the full screen.
+  // or without the overlaid views (e.g. infobar) and either of the visible
+  // frame of of the full screen.
   UIImage* GenerateSnapshot(bool with_overlays, bool visible_frame_only);
 
   // When snapshot coalescing is enabled, multiple calls to generate a
@@ -83,6 +90,7 @@
   SnapshotTabHelper(web::WebState* web_state, NSString* session_id);
 
   // web::WebStateObserver implementation.
+  void DidStartLoading(web::WebState* web_state) override;
   void PageLoaded(
       web::WebState* web_state,
       web::PageLoadCompletionStatus load_completion_status) override;
@@ -94,6 +102,10 @@
   bool ignore_next_load_ = false;
   bool pause_snapshotting_ = false;
 
+  // Used to ensure |UpdateSnapshotWithCallback()| is not run when this object
+  // is destroyed.
+  base::WeakPtrFactory<SnapshotTabHelper> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(SnapshotTabHelper);
 };
 
diff --git a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
index 7bcdeca..6a9c642 100644
--- a/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
+++ b/ios/chrome/browser/snapshots/snapshot_tab_helper.mm
@@ -4,11 +4,16 @@
 
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/task/post_task.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
 #import "ios/chrome/browser/snapshots/snapshot_generator.h"
+#include "ios/chrome/browser/ui/ui_util.h"
+#include "ios/web/public/web_task_traits.h"
+#include "ios/web/public/web_thread.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -122,6 +127,23 @@
   [snapshot_generator_ retrieveGreySnapshot:callback];
 }
 
+void SnapshotTabHelper::UpdateSnapshotWithCallback(void (^callback)(UIImage*)) {
+  if (IsWKWebViewSnapshotsEnabled() && web_state_->ContentIsHTML()) {
+    if (@available(iOS 11, *)) {
+      [snapshot_generator_ updateWebViewSnapshotWithCompletion:callback];
+      return;
+    }
+  }
+  // Pre-iOS 11 and native content cannot utilize the WKWebView snapshotting
+  // API.
+  UIImage* image =
+      UpdateSnapshot(/*with_overlays=*/true, /*visible_frame_only=*/true);
+  dispatch_async(dispatch_get_main_queue(), ^{
+    if (callback)
+      callback(image);
+  });
+}
+
 UIImage* SnapshotTabHelper::UpdateSnapshot(bool with_overlays,
                                            bool visible_frame_only) {
   return [snapshot_generator_ updateSnapshotWithOverlays:with_overlays
@@ -162,7 +184,7 @@
 
 SnapshotTabHelper::SnapshotTabHelper(web::WebState* web_state,
                                      NSString* session_id)
-    : web_state_(web_state) {
+    : web_state_(web_state), weak_ptr_factory_(this) {
   snapshot_generator_ = [[SnapshotGenerator alloc] initWithWebState:web_state_
                                                   snapshotSessionId:session_id];
 
@@ -176,11 +198,28 @@
   web_state_->AddObserver(this);
 }
 
+void SnapshotTabHelper::DidStartLoading(web::WebState* web_state) {
+  if (IsWKWebViewSnapshotsEnabled())
+    RemoveSnapshot();
+}
+
 void SnapshotTabHelper::PageLoaded(
     web::WebState* web_state,
     web::PageLoadCompletionStatus load_completion_status) {
   if (!ignore_next_load_ && !pause_snapshotting_ &&
       load_completion_status == web::PageLoadCompletionStatus::SUCCESS) {
+    if (IsWKWebViewSnapshotsEnabled() && web_state->ContentIsHTML()) {
+      if (@available(iOS 11, *)) {
+        base::PostDelayedTaskWithTraits(
+            FROM_HERE, {web::WebThread::UI},
+            base::BindOnce(&SnapshotTabHelper::UpdateSnapshotWithCallback,
+                           weak_ptr_factory_.GetWeakPtr(), /*callback=*/nil),
+            base::TimeDelta::FromSeconds(1));
+        return;
+      }
+    }
+    // Pre-iOS 11 and native content cannot utilize the WKWebView snapshotting
+    // API.
     UpdateSnapshot(/*with_overlays=*/true, /*visible_frame_only=*/true);
   }
   ignore_next_load_ = false;
diff --git a/ios/chrome/browser/sync/BUILD.gn b/ios/chrome/browser/sync/BUILD.gn
index c55af33..17c2bda 100644
--- a/ios/chrome/browser/sync/BUILD.gn
+++ b/ios/chrome/browser/sync/BUILD.gn
@@ -21,6 +21,8 @@
     "model_type_store_service_factory.h",
     "profile_sync_service_factory.cc",
     "profile_sync_service_factory.h",
+    "session_sync_service_factory.cc",
+    "session_sync_service_factory.h",
     "sync_observer_bridge.h",
     "sync_observer_bridge.mm",
     "sync_setup_service.cc",
@@ -121,12 +123,14 @@
   testonly = true
   sources = [
     "profile_sync_service_factory_unittest.cc",
+    "session_sync_service_factory_unittest.cc",
   ]
   deps = [
     ":sync",
     "//base",
     "//components/browser_sync",
     "//components/sync",
+    "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state:test_support",
     "//ios/web/public/test",
     "//testing/gtest",
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.h b/ios/chrome/browser/sync/ios_chrome_sync_client.h
index 988b4f2..803901d 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.h
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.h
@@ -45,6 +45,7 @@
   bookmarks::BookmarkModel* GetBookmarkModel() override;
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
+  sync_sessions::SessionSyncService* GetSessionSyncService() override;
   bool HasPasswordStore() override;
   base::Closure GetPasswordStateChangedCallback() override;
   syncer::DataTypeController::TypeVector CreateDataTypeControllers(
@@ -53,7 +54,6 @@
   invalidation::InvalidationService* GetInvalidationService() override;
   BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
   scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
-  sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override;
   base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
       syncer::ModelType type) override;
   base::WeakPtr<syncer::ModelTypeControllerDelegate>
@@ -84,8 +84,6 @@
   // The task runner for the |web_data_service_|, if any.
   scoped_refptr<base::SingleThreadTaskRunner> db_thread_;
 
-  std::unique_ptr<sync_sessions::SyncSessionsClient> sync_sessions_client_;
-
   DISALLOW_COPY_AND_ASSIGN(IOSChromeSyncClient);
 };
 
diff --git a/ios/chrome/browser/sync/ios_chrome_sync_client.mm b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
index 689158ca..014c4a50 100644
--- a/ios/chrome/browser/sync/ios_chrome_sync_client.mm
+++ b/ios/chrome/browser/sync/ios_chrome_sync_client.mm
@@ -36,7 +36,6 @@
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/search_engines/search_engine_data_type_controller.h"
 #include "components/sync/base/report_unrecoverable_error.h"
-#include "components/sync/device_info/local_device_info_provider.h"
 #include "components/sync/driver/sync_api_component_factory.h"
 #include "components/sync/driver/sync_util.h"
 #include "components/sync/engine/passive_model_worker.h"
@@ -45,17 +44,13 @@
 #include "components/sync/user_events/user_event_service.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/sync_sessions/favicon_cache.h"
-#include "components/sync_sessions/local_session_event_router.h"
-#include "components/sync_sessions/session_sync_bridge.h"
-#include "components/sync_sessions/sync_sessions_client.h"
-#include "components/sync_sessions/synced_window_delegates_getter.h"
+#include "components/sync_sessions/session_sync_service.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/bookmarks/bookmark_sync_service_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state_manager.h"
-#include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/dom_distiller/dom_distiller_service_factory.h"
 #include "ios/chrome/browser/favicon/favicon_service_factory.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
@@ -64,12 +59,10 @@
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
 #include "ios/chrome/browser/sync/consent_auditor_factory.h"
-#include "ios/chrome/browser/sync/glue/sync_start_util.h"
 #include "ios/chrome/browser/sync/ios_user_event_service_factory.h"
 #include "ios/chrome/browser/sync/model_type_store_service_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
-#include "ios/chrome/browser/sync/sessions/ios_chrome_local_session_event_router.h"
-#include "ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h"
+#include "ios/chrome/browser/sync/session_sync_service_factory.h"
 #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "ios/chrome/browser/web_data_service_factory.h"
 #include "ios/chrome/common/channel_info.h"
@@ -91,80 +84,10 @@
   return syncer::ModelTypeSetFromString(disabled_types_str);
 }
 
-// iOS implementation of SyncSessionsClient. Needs to be in a separate class
-// due to possible multiple inheritance issues, wherein IOSChromeSyncClient
-// might inherit from other interfaces with same methods.
-class SyncSessionsClientImpl : public sync_sessions::SyncSessionsClient {
- public:
-  explicit SyncSessionsClientImpl(ios::ChromeBrowserState* browser_state)
-      : browser_state_(browser_state),
-        window_delegates_getter_(
-            std::make_unique<TabModelSyncedWindowDelegatesGetter>()),
-        local_session_event_router_(
-            std::make_unique<IOSChromeLocalSessionEventRouter>(
-                browser_state_,
-                this,
-                ios::sync_start_util::GetFlareForSyncableService(
-                    browser_state_->GetStatePath()))) {}
-
-  ~SyncSessionsClientImpl() override {}
-
-  // SyncSessionsClient implementation.
-  favicon::FaviconService* GetFaviconService() override {
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-    return ios::FaviconServiceFactory::GetForBrowserState(
-        browser_state_, ServiceAccessType::IMPLICIT_ACCESS);
-  }
-
-  history::HistoryService* GetHistoryService() override {
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-    return ios::HistoryServiceFactory::GetForBrowserState(
-        browser_state_, ServiceAccessType::EXPLICIT_ACCESS);
-  }
-
-  const syncer::DeviceInfo* GetLocalDeviceInfo() override {
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-    return ProfileSyncServiceFactory::GetForBrowserState(browser_state_)
-        ->GetLocalDeviceInfoProvider()
-        ->GetLocalDeviceInfo();
-  }
-
-  bool ShouldSyncURL(const GURL& url) const override {
-    if (url == kChromeUIHistoryURL) {
-      // The history page is treated specially as we want it to trigger syncable
-      // events for UI purposes.
-      return true;
-    }
-    return url.is_valid() && !url.SchemeIs(kChromeUIScheme) &&
-           !url.SchemeIsFile();
-  }
-
-  sync_sessions::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter()
-      override {
-    return window_delegates_getter_.get();
-  }
-
-  sync_sessions::LocalSessionEventRouter* GetLocalSessionEventRouter()
-      override {
-    return local_session_event_router_.get();
-  }
-
- private:
-  ios::ChromeBrowserState* const browser_state_;
-  const std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter>
-      window_delegates_getter_;
-  const std::unique_ptr<IOSChromeLocalSessionEventRouter>
-      local_session_event_router_;
-
-  DISALLOW_COPY_AND_ASSIGN(SyncSessionsClientImpl);
-};
-
 }  // namespace
 
 IOSChromeSyncClient::IOSChromeSyncClient(ios::ChromeBrowserState* browser_state)
-    : browser_state_(browser_state),
-      sync_sessions_client_(
-          std::make_unique<SyncSessionsClientImpl>(browser_state)) {
+    : browser_state_(browser_state) {
   profile_web_data_service_ =
       ios::WebDataServiceFactory::GetAutofillWebDataForBrowserState(
           browser_state_, ServiceAccessType::IMPLICIT_ACCESS);
@@ -231,6 +154,12 @@
       browser_state_, ServiceAccessType::EXPLICIT_ACCESS);
 }
 
+sync_sessions::SessionSyncService*
+IOSChromeSyncClient::GetSessionSyncService() {
+  DCHECK_CURRENTLY_ON(web::WebThread::UI);
+  return SessionSyncServiceFactory::GetForBrowserState(browser_state_);
+}
+
 bool IOSChromeSyncClient::HasPasswordStore() {
   DCHECK_CURRENTLY_ON(web::WebThread::UI);
   return password_store_ != nullptr;
@@ -276,11 +205,6 @@
   return nullptr;
 }
 
-sync_sessions::SyncSessionsClient*
-IOSChromeSyncClient::GetSyncSessionsClient() {
-  return sync_sessions_client_.get();
-}
-
 base::WeakPtr<syncer::SyncableService>
 IOSChromeSyncClient::GetSyncableServiceForType(syncer::ModelType type) {
   switch (type) {
@@ -320,7 +244,7 @@
     case syncer::FAVICON_IMAGES:
     case syncer::FAVICON_TRACKING: {
       sync_sessions::FaviconCache* favicons =
-          ProfileSyncServiceFactory::GetForBrowserState(browser_state_)
+          SessionSyncServiceFactory::GetForBrowserState(browser_state_)
               ->GetFaviconCache();
       return favicons ? favicons->AsWeakPtr()
                       : base::WeakPtr<syncer::SyncableService>();
@@ -333,8 +257,8 @@
       return base::WeakPtr<syncer::SyncableService>();
     }
     case syncer::SESSIONS: {
-      return ProfileSyncServiceFactory::GetForBrowserState(browser_state_)
-          ->GetSessionsSyncableService()
+      return SessionSyncServiceFactory::GetForBrowserState(browser_state_)
+          ->GetSyncableService()
           ->AsWeakPtr();
     }
     case syncer::PASSWORDS: {
@@ -368,9 +292,6 @@
           ->GetSyncBridge()
           ->change_processor()
           ->GetControllerDelegate();
-    case syncer::SESSIONS:
-      return ProfileSyncServiceFactory::GetForBrowserState(browser_state_)
-          ->GetSessionSyncControllerDelegate();
 
     // We don't exercise this function for certain datatypes, because their
     // controllers get the delegate elsewhere.
@@ -379,6 +300,7 @@
     case syncer::AUTOFILL_WALLET_DATA:
     case syncer::AUTOFILL_WALLET_METADATA:
     case syncer::BOOKMARKS:
+    case syncer::SESSIONS:
     case syncer::TYPED_URLS:
       NOTREACHED();
       return base::WeakPtr<syncer::ModelTypeControllerDelegate>();
diff --git a/ios/chrome/browser/sync/ios_user_event_service_factory.cc b/ios/chrome/browser/sync/ios_user_event_service_factory.cc
index 3469d25..cfd41c5 100644
--- a/ios/chrome/browser/sync/ios_user_event_service_factory.cc
+++ b/ios/chrome/browser/sync/ios_user_event_service_factory.cc
@@ -17,10 +17,12 @@
 #include "components/sync/user_events/no_op_user_event_service.h"
 #include "components/sync/user_events/user_event_service_impl.h"
 #include "components/sync/user_events/user_event_sync_bridge.h"
+#include "components/sync_sessions/session_sync_service.h"
 #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/sync/model_type_store_service_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
+#include "ios/chrome/browser/sync/session_sync_service_factory.h"
 #include "ios/chrome/common/channel_info.h"
 #include "ios/web/public/browser_state.h"
 
@@ -41,6 +43,7 @@
           "UserEventService",
           BrowserStateDependencyManager::GetInstance()) {
   DependsOn(ModelTypeStoreServiceFactory::GetInstance());
+  DependsOn(SessionSyncServiceFactory::GetInstance());
 }
 
 IOSUserEventServiceFactory::~IOSUserEventServiceFactory() {}
@@ -66,7 +69,8 @@
       std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
           syncer::USER_EVENTS, /*dump_stack=*/base::BindRepeating(
               &syncer::ReportUnrecoverableError, ::GetChannel())),
-      sync_service->GetGlobalIdMapper());
+      SessionSyncServiceFactory::GetForBrowserState(browser_state)
+          ->GetGlobalIdMapper());
   return std::make_unique<syncer::UserEventServiceImpl>(sync_service,
                                                         std::move(bridge));
 }
diff --git a/ios/chrome/browser/sync/profile_sync_service_factory.cc b/ios/chrome/browser/sync/profile_sync_service_factory.cc
index 8d2d3b1..b11737b 100644
--- a/ios/chrome/browser/sync/profile_sync_service_factory.cc
+++ b/ios/chrome/browser/sync/profile_sync_service_factory.cc
@@ -34,6 +34,7 @@
 #include "ios/chrome/browser/sync/consent_auditor_factory.h"
 #include "ios/chrome/browser/sync/ios_chrome_sync_client.h"
 #include "ios/chrome/browser/sync/model_type_store_service_factory.h"
+#include "ios/chrome/browser/sync/session_sync_service_factory.h"
 #include "ios/chrome/browser/undo/bookmark_undo_service_factory.h"
 #include "ios/chrome/browser/web_data_service_factory.h"
 #include "ios/chrome/common/channel_info.h"
@@ -113,6 +114,7 @@
   DependsOn(IOSChromeProfileInvalidationProviderFactory::GetInstance());
   DependsOn(ModelTypeStoreServiceFactory::GetInstance());
   DependsOn(ReadingListModelFactory::GetInstance());
+  DependsOn(SessionSyncServiceFactory::GetInstance());
 }
 
 ProfileSyncServiceFactory::~ProfileSyncServiceFactory() {}
diff --git a/ios/chrome/browser/sync/session_sync_service_factory.cc b/ios/chrome/browser/sync/session_sync_service_factory.cc
new file mode 100644
index 0000000..bb4f64e
--- /dev/null
+++ b/ios/chrome/browser/sync/session_sync_service_factory.cc
@@ -0,0 +1,172 @@
+// 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 "ios/chrome/browser/sync/session_sync_service_factory.h"
+
+#include <utility>
+
+#include "base/memory/singleton.h"
+#include "base/task/post_task.h"
+#include "base/time/time.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/keyed_service/core/service_access_type.h"
+#include "components/keyed_service/ios/browser_state_dependency_manager.h"
+#include "components/sync/device_info/local_device_info_provider.h"
+#include "components/sync/model/model_type_store_service.h"
+#include "components/sync_sessions/local_session_event_router.h"
+#include "components/sync_sessions/session_sync_prefs.h"
+#include "components/sync_sessions/session_sync_service.h"
+#include "components/sync_sessions/sync_sessions_client.h"
+#include "components/sync_sessions/synced_window_delegates_getter.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/chrome_url_constants.h"
+#include "ios/chrome/browser/favicon/favicon_service_factory.h"
+#include "ios/chrome/browser/history/history_service_factory.h"
+#include "ios/chrome/browser/sync/glue/sync_start_util.h"
+#include "ios/chrome/browser/sync/model_type_store_service_factory.h"
+#include "ios/chrome/browser/sync/profile_sync_service_factory.h"
+#include "ios/chrome/browser/sync/sessions/ios_chrome_local_session_event_router.h"
+#include "ios/chrome/browser/tabs/tab_model_synced_window_delegate_getter.h"
+#include "ios/chrome/common/channel_info.h"
+#include "ios/web/public/web_thread.h"
+#include "url/gurl.h"
+
+using sync_sessions::SessionSyncService;
+
+namespace {
+
+bool ShouldSyncURLImpl(const GURL& url) {
+  if (url == kChromeUIHistoryURL) {
+    // Whitelist the chrome history page, home for "Tabs from other devices",
+    // so it can trigger starting up the sync engine.
+    return true;
+  }
+  return url.is_valid() && !url.SchemeIs(kChromeUIScheme) &&
+         !url.SchemeIsFile();
+}
+
+// iOS implementation of SyncSessionsClient. Needs to be in a separate class
+// due to possible multiple inheritance issues, wherein IOSChromeSyncClient
+// might inherit from other interfaces with same methods.
+class SyncSessionsClientImpl : public sync_sessions::SyncSessionsClient {
+ public:
+  explicit SyncSessionsClientImpl(ios::ChromeBrowserState* browser_state)
+      : browser_state_(browser_state),
+        window_delegates_getter_(
+            std::make_unique<TabModelSyncedWindowDelegatesGetter>()),
+        local_session_event_router_(
+            std::make_unique<IOSChromeLocalSessionEventRouter>(
+                browser_state_,
+                this,
+                ios::sync_start_util::GetFlareForSyncableService(
+                    browser_state_->GetStatePath()))),
+        session_sync_prefs_(browser_state->GetPrefs()) {}
+
+  ~SyncSessionsClientImpl() override {}
+
+  // SyncSessionsClient implementation.
+  favicon::FaviconService* GetFaviconService() override {
+    DCHECK_CURRENTLY_ON(web::WebThread::UI);
+    return ios::FaviconServiceFactory::GetForBrowserState(
+        browser_state_, ServiceAccessType::IMPLICIT_ACCESS);
+  }
+
+  history::HistoryService* GetHistoryService() override {
+    DCHECK_CURRENTLY_ON(web::WebThread::UI);
+    return ios::HistoryServiceFactory::GetForBrowserState(
+        browser_state_, ServiceAccessType::EXPLICIT_ACCESS);
+  }
+
+  sync_sessions::SessionSyncPrefs* GetSessionSyncPrefs() override {
+    return &session_sync_prefs_;
+  }
+
+  syncer::RepeatingModelTypeStoreFactory GetStoreFactory() override {
+    return ModelTypeStoreServiceFactory::GetForBrowserState(browser_state_)
+        ->GetStoreFactory();
+  }
+
+  const syncer::DeviceInfo* GetLocalDeviceInfo() override {
+    DCHECK_CURRENTLY_ON(web::WebThread::UI);
+    browser_sync::ProfileSyncService* profile_sync_service =
+        ProfileSyncServiceFactory::GetForBrowserStateIfExists(browser_state_);
+    if (!profile_sync_service) {
+      return nullptr;
+    }
+    return profile_sync_service->GetLocalDeviceInfoProvider()
+        ->GetLocalDeviceInfo();
+  }
+
+  bool ShouldSyncURL(const GURL& url) const override {
+    return ShouldSyncURLImpl(url);
+  }
+
+  sync_sessions::SyncedWindowDelegatesGetter* GetSyncedWindowDelegatesGetter()
+      override {
+    return window_delegates_getter_.get();
+  }
+
+  sync_sessions::LocalSessionEventRouter* GetLocalSessionEventRouter()
+      override {
+    return local_session_event_router_.get();
+  }
+
+  void NotifyForeignSessionUpdated() override {
+    DCHECK_CURRENTLY_ON(web::WebThread::UI);
+    browser_sync::ProfileSyncService* profile_sync_service =
+        ProfileSyncServiceFactory::GetForBrowserStateIfExists(browser_state_);
+    if (profile_sync_service) {
+      profile_sync_service->NotifyForeignSessionUpdated();
+    }
+  }
+
+ private:
+  ios::ChromeBrowserState* const browser_state_;
+  const std::unique_ptr<sync_sessions::SyncedWindowDelegatesGetter>
+      window_delegates_getter_;
+  const std::unique_ptr<IOSChromeLocalSessionEventRouter>
+      local_session_event_router_;
+  sync_sessions::SessionSyncPrefs session_sync_prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(SyncSessionsClientImpl);
+};
+
+}  // namespace
+
+// static
+SessionSyncServiceFactory* SessionSyncServiceFactory::GetInstance() {
+  return base::Singleton<SessionSyncServiceFactory>::get();
+}
+
+// static
+bool SessionSyncServiceFactory::ShouldSyncURLForTesting(const GURL& url) {
+  return ShouldSyncURLImpl(url);
+}
+
+// static
+SessionSyncService* SessionSyncServiceFactory::GetForBrowserState(
+    ios::ChromeBrowserState* browser_state) {
+  return static_cast<SessionSyncService*>(
+      GetInstance()->GetServiceForBrowserState(browser_state, true));
+}
+
+SessionSyncServiceFactory::SessionSyncServiceFactory()
+    : BrowserStateKeyedServiceFactory(
+          "SessionSyncService",
+          BrowserStateDependencyManager::GetInstance()) {
+  DependsOn(ios::FaviconServiceFactory::GetInstance());
+  DependsOn(ios::HistoryServiceFactory::GetInstance());
+  DependsOn(ModelTypeStoreServiceFactory::GetInstance());
+}
+
+SessionSyncServiceFactory::~SessionSyncServiceFactory() {}
+
+std::unique_ptr<KeyedService>
+SessionSyncServiceFactory::BuildServiceInstanceFor(
+    web::BrowserState* context) const {
+  ios::ChromeBrowserState* browser_state =
+      ios::ChromeBrowserState::FromBrowserState(context);
+  return std::make_unique<sync_sessions::SessionSyncService>(
+      ::GetChannel(), std::make_unique<SyncSessionsClientImpl>(browser_state));
+}
diff --git a/ios/chrome/browser/sync/session_sync_service_factory.h b/ios/chrome/browser/sync/session_sync_service_factory.h
new file mode 100644
index 0000000..552fa15
--- /dev/null
+++ b/ios/chrome/browser/sync/session_sync_service_factory.h
@@ -0,0 +1,52 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_
+#define IOS_CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+
+class GURL;
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}  // namespace base
+
+namespace sync_sessions {
+class SessionSyncService;
+}  // namespace sync_sessions
+
+namespace ios {
+class ChromeBrowserState;
+}  // namespace ios
+
+// Singleton that owns all SessionSyncService and associates them with
+// ios::ChromeBrowserState.
+class SessionSyncServiceFactory : public BrowserStateKeyedServiceFactory {
+ public:
+  static sync_sessions::SessionSyncService* GetForBrowserState(
+      ios::ChromeBrowserState* browser_state);
+
+  static SessionSyncServiceFactory* GetInstance();
+
+  static bool ShouldSyncURLForTesting(const GURL& url);
+
+ private:
+  friend struct base::DefaultSingletonTraits<SessionSyncServiceFactory>;
+
+  SessionSyncServiceFactory();
+  ~SessionSyncServiceFactory() override;
+
+  // BrowserStateKeyedServiceFactory implementation.
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      web::BrowserState* context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(SessionSyncServiceFactory);
+};
+
+#endif  // IOS_CHROME_BROWSER_SYNC_SESSION_SYNC_SERVICE_FACTORY_H_
diff --git a/ios/chrome/browser/sync/session_sync_service_factory_unittest.cc b/ios/chrome/browser/sync/session_sync_service_factory_unittest.cc
new file mode 100644
index 0000000..d43dc1e
--- /dev/null
+++ b/ios/chrome/browser/sync/session_sync_service_factory_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/chrome/browser/sync/session_sync_service_factory.h"
+
+#include "ios/chrome/browser/chrome_url_constants.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+
+const char kValidUrl[] = "http://www.example.com";
+const char kInvalidUrl[] = "invalid.url";
+
+TEST(SessionSyncServiceFactoryTest, ShouldSyncURL) {
+  EXPECT_TRUE(
+      SessionSyncServiceFactory::ShouldSyncURLForTesting(GURL(kValidUrl)));
+  EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL("other://anything")));
+  EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL("chrome-other://anything")));
+
+  EXPECT_FALSE(
+      SessionSyncServiceFactory::ShouldSyncURLForTesting(GURL(kInvalidUrl)));
+  EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL("file://anything")));
+  EXPECT_FALSE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL("chrome://anything")));
+
+  EXPECT_TRUE(SessionSyncServiceFactory::ShouldSyncURLForTesting(
+      GURL(kChromeUIHistoryURL)));
+}
+
+}  // namespace
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index 129c6658..934e7a0 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -100,6 +100,7 @@
 #include "net/cert/x509_certificate.h"
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_fetcher.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/page_transition_types.h"
 #include "url/origin.h"
@@ -462,8 +463,8 @@
 - (OpenInController*)openInController {
   if (!_openInController) {
     _openInController = [[OpenInController alloc]
-        initWithRequestContext:_browserState->GetRequestContext()
-                 webController:self.webController];
+        initWithURLLoaderFactory:_browserState->GetSharedURLLoaderFactory()
+                   webController:self.webController];
     _openInController.baseView = self.view;
   }
   return _openInController;
diff --git a/ios/chrome/browser/tabs/tab_model_unittest.mm b/ios/chrome/browser/tabs/tab_model_unittest.mm
index 3caf654..6c82084 100644
--- a/ios/chrome/browser/tabs/tab_model_unittest.mm
+++ b/ios/chrome/browser/tabs/tab_model_unittest.mm
@@ -7,6 +7,7 @@
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
@@ -29,6 +30,7 @@
 #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
 #import "ios/web/public/crw_session_storage.h"
+#include "ios/web/public/features.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/referrer.h"
 #import "ios/web/public/serializable_user_data_manager.h"
@@ -72,7 +74,16 @@
 const char kURL1[] = "https://www.some.url.com";
 const char kURL2[] = "https://www.some.url2.com";
 
-class TabModelTest : public PlatformTest {
+// TabModelTest is parameterized on this enum to test both
+// LegacyNavigationManager and WKBasedNavigationManager.
+enum class NavigationManagerChoice {
+  LEGACY,
+  WK_BASED,
+};
+
+class TabModelTest
+    : public PlatformTest,
+      public ::testing::WithParamInterface<NavigationManagerChoice> {
  public:
   TabModelTest()
       : scoped_browser_state_manager_(
@@ -80,6 +91,14 @@
         web_client_(std::make_unique<ChromeWebClient>()) {
     DCHECK_CURRENTLY_ON(web::WebThread::UI);
 
+    if (GetParam() == NavigationManagerChoice::LEGACY) {
+      scoped_feature_list_.InitAndDisableFeature(
+          web::features::kSlimNavigationManager);
+    } else {
+      scoped_feature_list_.InitAndEnableFeature(
+          web::features::kSlimNavigationManager);
+    }
+
     TestChromeBrowserState::Builder test_cbs_builder;
     chrome_browser_state_ = test_cbs_builder.Build();
 
@@ -147,9 +166,10 @@
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
   WebStateListWebUsageEnabler* web_usage_enabler_;
   TabModel* tab_model_;
+  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
-TEST_F(TabModelTest, IsEmpty) {
+TEST_P(TabModelTest, IsEmpty) {
   EXPECT_EQ([tab_model_ count], 0U);
   EXPECT_TRUE([tab_model_ isEmpty]);
   [tab_model_ insertTabWithURL:GURL(kURL1)
@@ -163,7 +183,7 @@
   EXPECT_FALSE([tab_model_ isEmpty]);
 }
 
-TEST_F(TabModelTest, InsertUrlSingle) {
+TEST_P(TabModelTest, InsertUrlSingle) {
   Tab* tab = [tab_model_ insertTabWithURL:GURL(kURL1)
                                  referrer:web::Referrer()
                                transition:ui::PAGE_TRANSITION_TYPED
@@ -175,7 +195,7 @@
   EXPECT_NSEQ(tab, [tab_model_ tabAtIndex:0]);
 }
 
-TEST_F(TabModelTest, InsertUrlMultiple) {
+TEST_P(TabModelTest, InsertUrlMultiple) {
   Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
                                   referrer:web::Referrer()
                                 transition:ui::PAGE_TRANSITION_TYPED
@@ -204,7 +224,7 @@
   EXPECT_NSEQ(tab0, [tab_model_ tabAtIndex:2]);
 }
 
-TEST_F(TabModelTest, AppendUrlSingle) {
+TEST_P(TabModelTest, AppendUrlSingle) {
   Tab* tab = [tab_model_ insertTabWithURL:GURL(kURL1)
                                  referrer:web::Referrer()
                                transition:ui::PAGE_TRANSITION_TYPED
@@ -216,7 +236,7 @@
   EXPECT_NSEQ(tab, [tab_model_ tabAtIndex:0]);
 }
 
-TEST_F(TabModelTest, AppendUrlMultiple) {
+TEST_P(TabModelTest, AppendUrlMultiple) {
   Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
                                   referrer:web::Referrer()
                                 transition:ui::PAGE_TRANSITION_TYPED
@@ -245,7 +265,7 @@
   EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:2]);
 }
 
-TEST_F(TabModelTest, CloseTabAtIndexBeginning) {
+TEST_P(TabModelTest, CloseTabAtIndexBeginning) {
   [tab_model_ insertTabWithURL:GURL(kURL1)
                       referrer:web::Referrer()
                     transition:ui::PAGE_TRANSITION_TYPED
@@ -275,7 +295,7 @@
   EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]);
 }
 
-TEST_F(TabModelTest, CloseTabAtIndexMiddle) {
+TEST_P(TabModelTest, CloseTabAtIndexMiddle) {
   Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
                                   referrer:web::Referrer()
                                 transition:ui::PAGE_TRANSITION_TYPED
@@ -305,7 +325,7 @@
   EXPECT_NSEQ(tab2, [tab_model_ tabAtIndex:1]);
 }
 
-TEST_F(TabModelTest, CloseTabAtIndexLast) {
+TEST_P(TabModelTest, CloseTabAtIndexLast) {
   Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
                                   referrer:web::Referrer()
                                 transition:ui::PAGE_TRANSITION_TYPED
@@ -335,7 +355,7 @@
   EXPECT_NSEQ(tab1, [tab_model_ tabAtIndex:1]);
 }
 
-TEST_F(TabModelTest, CloseTabAtIndexOnlyOne) {
+TEST_P(TabModelTest, CloseTabAtIndexOnlyOne) {
   [tab_model_ insertTabWithURL:GURL(kURL1)
                       referrer:web::Referrer()
                     transition:ui::PAGE_TRANSITION_TYPED
@@ -349,7 +369,12 @@
   EXPECT_EQ(0U, [tab_model_ count]);
 }
 
-TEST_F(TabModelTest, RestoreSessionOnNTPTest) {
+TEST_P(TabModelTest, RestoreSessionOnNTPTest) {
+  // TODO(crbug.com/888674): migrate this to EG test so it can be tested with
+  // WKBasedNavigationManager.
+  if (web_client_.Get()->IsSlimNavigationManagerEnabled())
+    return;
+
   Tab* tab = [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL)
                                  referrer:web::Referrer()
                                transition:ui::PAGE_TRANSITION_TYPED
@@ -370,7 +395,12 @@
   EXPECT_NSNE(tab, [tab_model_ tabAtIndex:2]);
 }
 
-TEST_F(TabModelTest, RestoreSessionOn2NtpTest) {
+TEST_P(TabModelTest, RestoreSessionOn2NtpTest) {
+  // TODO(crbug.com/888674): migrate this to EG test so it can be tested with
+  // WKBasedNavigationManager.
+  if (web_client_.Get()->IsSlimNavigationManagerEnabled())
+    return;
+
   Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kChromeUINewTabURL)
                                   referrer:web::Referrer()
                                 transition:ui::PAGE_TRANSITION_TYPED
@@ -405,7 +435,12 @@
   EXPECT_NSNE(tab1, [tab_model_ tabAtIndex:4]);
 }
 
-TEST_F(TabModelTest, RestoreSessionOnAnyTest) {
+TEST_P(TabModelTest, RestoreSessionOnAnyTest) {
+  // TODO(crbug.com/888674): migrate this to EG test so it can be tested with
+  // WKBasedNavigationManager.
+  if (web_client_.Get()->IsSlimNavigationManagerEnabled())
+    return;
+
   Tab* tab = [tab_model_ insertTabWithURL:GURL(kURL1)
                                  referrer:web::Referrer()
                                transition:ui::PAGE_TRANSITION_TYPED
@@ -427,7 +462,7 @@
   EXPECT_NSNE(tab, [tab_model_ tabAtIndex:3]);
 }
 
-TEST_F(TabModelTest, CloseAllTabs) {
+TEST_P(TabModelTest, CloseAllTabs) {
   [tab_model_ insertTabWithURL:GURL(kURL1)
                       referrer:web::Referrer()
                     transition:ui::PAGE_TRANSITION_TYPED
@@ -455,13 +490,13 @@
   EXPECT_EQ(0U, [tab_model_ count]);
 }
 
-TEST_F(TabModelTest, CloseAllTabsWithNoTabs) {
+TEST_P(TabModelTest, CloseAllTabsWithNoTabs) {
   [tab_model_ closeAllTabs];
 
   EXPECT_EQ(0U, [tab_model_ count]);
 }
 
-TEST_F(TabModelTest, InsertWithSessionController) {
+TEST_P(TabModelTest, InsertWithSessionController) {
   EXPECT_EQ([tab_model_ count], 0U);
   EXPECT_TRUE([tab_model_ isEmpty]);
 
@@ -479,7 +514,7 @@
   EXPECT_TRUE(current_tab);
 }
 
-TEST_F(TabModelTest, AddWithOrderController) {
+TEST_P(TabModelTest, AddWithOrderController) {
   // Create a few tabs with the controller at the front.
   Tab* parent = [tab_model_ insertTabWithURL:GURL(kURL1)
                                     referrer:web::Referrer()
@@ -559,7 +594,7 @@
   EXPECT_EQ([tab_model_ indexOfTab:tab4], [tab_model_ indexOfTab:tab3] + 1);
 }
 
-TEST_F(TabModelTest, MoveTabs) {
+TEST_P(TabModelTest, MoveTabs) {
   Tab* tab0 = [tab_model_ insertTabWithURL:GURL(kURL1)
                                   referrer:web::Referrer()
                                 transition:ui::PAGE_TRANSITION_TYPED
@@ -643,7 +678,7 @@
   [tab_model_ removeObserver:tab_model_observer];
 }
 
-TEST_F(TabModelTest, ParentTabModel) {
+TEST_P(TabModelTest, ParentTabModel) {
   std::unique_ptr<web::WebState> web_state = web::WebState::Create(
       web::WebState::CreateParams(chrome_browser_state_.get()));
   AttachTabHelpers(web_state.get(), /*for_prerender=*/false);
@@ -657,7 +692,7 @@
   EXPECT_NSEQ(tab_model_, [tab parentTabModel]);
 }
 
-TEST_F(TabModelTest, TabCreatedOnInsertion) {
+TEST_P(TabModelTest, TabCreatedOnInsertion) {
   std::unique_ptr<web::WebState> web_state = web::WebState::Create(
       web::WebState::CreateParams(chrome_browser_state_.get()));
 
@@ -670,7 +705,7 @@
   EXPECT_NSNE(nil, LegacyTabHelper::GetTabForWebState(web_state_ptr));
 }
 
-TEST_F(TabModelTest, PersistSelectionChange) {
+TEST_P(TabModelTest, PersistSelectionChange) {
   NSString* stashPath =
       base::SysUTF8ToNSString(chrome_browser_state_->GetStatePath().value());
 
@@ -729,4 +764,9 @@
                                                          error:nullptr]);
 }
 
+INSTANTIATE_TEST_CASE_P(ProgrammaticTabModelTest,
+                        TabModelTest,
+                        ::testing::Values(NavigationManagerChoice::LEGACY,
+                                          NavigationManagerChoice::WK_BASED));
+
 }  // anonymous namespace
diff --git a/ios/chrome/browser/ui/BUILD.gn b/ios/chrome/browser/ui/BUILD.gn
index 12d09e83..d9f651b 100644
--- a/ios/chrome/browser/ui/BUILD.gn
+++ b/ios/chrome/browser/ui/BUILD.gn
@@ -156,6 +156,7 @@
     "//ios/web/public/test/fakes",
     "//net",
     "//net:test_support",
+    "//services/network:test_support",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/ocmock",
@@ -369,7 +370,6 @@
     "//ios/chrome/browser/ui/history",
     "//ios/chrome/browser/ui/image_util",
     "//ios/chrome/browser/ui/keyboard",
-    "//ios/chrome/browser/ui/main:feature_flags",
     "//ios/chrome/browser/ui/main:tab_switcher",
     "//ios/chrome/browser/ui/main_content:main_content_ui",
     "//ios/chrome/browser/ui/main_content:main_content_ui_broadcasting_util",
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm
index 55ab424..e527160 100644
--- a/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm
+++ b/ios/chrome/browser/ui/autofill/form_input_accessory_coordinator.mm
@@ -9,6 +9,7 @@
 #import "ios/chrome/browser/autofill/form_input_accessory_view_controller.h"
 #import "ios/chrome/browser/ui/autofill/form_input_accessory_mediator.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_accessory_view_controller.h"
+#import "ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -30,6 +31,11 @@
 @property(nonatomic, strong)
     ManualFillAccessoryViewController* manualFillAccessoryViewController;
 
+// The object in charge of interacting with the web view. Used to fill the data
+// in the forms.
+@property(nonatomic, strong)
+    ManualFillInjectionHandler* manualFillInjectionHandler;
+
 // The WebStateList for this instance. Used to instantiate the child
 // coordinators lazily.
 @property(nonatomic, assign) WebStateList* webStateList;
@@ -44,6 +50,7 @@
 @synthesize manualFillAccessoryViewController =
     _manualFillAccessoryViewController;
 @synthesize webStateList = _webStateList;
+@synthesize manualFillInjectionHandler = _manualFillInjectionHandler;
 
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
                               browserState:
@@ -56,6 +63,9 @@
   if (self) {
     _webStateList = webStateList;
 
+    _manualFillInjectionHandler =
+        [[ManualFillInjectionHandler alloc] initWithWebStateList:webStateList];
+
     _formInputAccessoryViewController =
         [[FormInputAccessoryViewController alloc] init];
 
@@ -91,7 +101,8 @@
       [[ManualFillPasswordCoordinator alloc]
           initWithBaseViewController:self.baseViewController
                         browserState:self.browserState
-                        webStateList:self.webStateList];
+                        webStateList:self.webStateList
+                    injectionHandler:self.manualFillInjectionHandler];
   [self.formInputAccessoryViewController
       presentView:passwordCoordinator.viewController.view];
   [self.childCoordinators addObject:passwordCoordinator];
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
index 63ebd30..056cd39b 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
@@ -8,6 +8,8 @@
   sources = [
     "credential_password_form.h",
     "credential_password_form.mm",
+    "form_observer_helper.h",
+    "form_observer_helper.mm",
     "manual_fill_injection_handler.h",
     "manual_fill_injection_handler.mm",
     "password_coordinator.h",
@@ -19,6 +21,7 @@
     "//base",
     "//components/autofill/core/common",
     "//components/autofill/ios/browser",
+    "//components/autofill/ios/form_util",
     "//components/keyed_service/core:core",
     "//components/password_manager/core/browser",
     "//ios/chrome/app/strings:ios_strings_grit",
@@ -83,13 +86,20 @@
   sources = [
     "credential_password_form_unittest.mm",
     "credential_unittest.mm",
+    "form_observer_helper_unittest.mm",
   ]
   deps = [
     ":manual_fill",
     ":manual_fill_ui",
     "//base:base",
     "//components/autofill/core/common:common",
+    "//components/autofill/ios/form_util:form_util",
+    "//components/autofill/ios/form_util:test_support",
+    "//ios/chrome/browser/web_state_list:test_support",
+    "//ios/chrome/browser/web_state_list:web_state_list",
+    "//ios/web/public/test/fakes:fakes",
     "//testing/gtest:gtest",
+    "//third_party/ocmock:ocmock",
     "//url:url",
   ]
 }
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h
new file mode 100644
index 0000000..60e4f928
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h
@@ -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.
+
+#ifndef IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_FORM_OBSERVER_HELPER_H_
+#define IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_FORM_OBSERVER_HELPER_H_
+
+#import <Foundation/Foundation.h>
+
+@protocol FormActivityObserver;
+class WebStateList;
+
+// Convenience object to observe updates in forms. It abstracts all the logic
+// to observe a web state list and its web states.
+@interface FormObserverHelper : NSObject
+
+// The delegate interested in the form activity.
+@property(nonatomic, weak) id<FormActivityObserver> delegate;
+
+// Returns a fresh object observing the active web state for the passed list.
+- (instancetype)initWithWebStateList:(WebStateList*)webStateList;
+
+// Not available. Use |initWithWebStateList:|.
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_AUTOFILL_MANUAL_FILL_FORM_OBSERVER_HELPER_H_
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm
new file mode 100644
index 0000000..6d9026c
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.mm
@@ -0,0 +1,125 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h"
+
+#import "components/autofill/ios/form_util/form_activity_observer_bridge.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
+#include "ios/web/public/web_state/web_state.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@interface FormObserverHelper ()<FormActivityObserver, WebStateListObserving>
+// The WebStateList this instance is observing in order to update the
+// active WebState.
+@property(nonatomic, assign) WebStateList* webStateList;
+
+// The WebState this instance is observing. Can be nullptr.
+@property(nonatomic, assign) web::WebState* webState;
+
+@end
+
+@implementation FormObserverHelper {
+  // Bridge to observe the web state list from Objective-C.
+  std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
+
+  // Bridge to observe form activity in |_webState|.
+  std::unique_ptr<autofill::FormActivityObserverBridge>
+      _formActivityObserverBridge;
+}
+
+@synthesize delegate = _delegate;
+
+- (instancetype)initWithWebStateList:(WebStateList*)webStateList {
+  DCHECK(webStateList);
+  self = [super init];
+  if (self) {
+    _webStateList = webStateList;
+    _webStateListObserver = std::make_unique<WebStateListObserverBridge>(self);
+    _webStateList->AddObserver(_webStateListObserver.get());
+    web::WebState* webState = webStateList->GetActiveWebState();
+    if (webState) {
+      _webState = webState;
+      _formActivityObserverBridge =
+          std::make_unique<autofill::FormActivityObserverBridge>(_webState,
+                                                                 self);
+    }
+  }
+  return self;
+}
+
+- (void)dealloc {
+  if (_webState) {
+    _formActivityObserverBridge.reset();
+    _webState = nullptr;
+  }
+  if (_webStateList) {
+    _webStateList->RemoveObserver(_webStateListObserver.get());
+    _webStateListObserver.reset();
+    _webStateList = nullptr;
+  }
+  _formActivityObserverBridge.reset();
+}
+
+#pragma mark - FormActivityObserver
+
+- (void)webState:(web::WebState*)webState
+    didRegisterFormActivity:(const autofill::FormActivityParams&)params
+                    inFrame:(web::WebFrame*)frame {
+  if ([self.delegate respondsToSelector:@selector
+                     (webState:didRegisterFormActivity:inFrame:)]) {
+    [self.delegate webState:webState
+        didRegisterFormActivity:params
+                        inFrame:frame];
+  }
+}
+
+- (void)webState:(web::WebState*)webState
+    didSubmitDocumentWithFormNamed:(const std::string&)formName
+                          withData:(const std::string&)formData
+                    hasUserGesture:(BOOL)hasUserGesture
+                   formInMainFrame:(BOOL)formInMainFrame
+                           inFrame:(web::WebFrame*)frame {
+  if ([self.delegate respondsToSelector:@selector
+                     (webState:didSubmitDocumentWithFormNamed:withData
+                                 :hasUserGesture:formInMainFrame:inFrame:)]) {
+    [self.delegate webState:webState
+        didSubmitDocumentWithFormNamed:formName
+                              withData:formData
+                        hasUserGesture:hasUserGesture
+                       formInMainFrame:formInMainFrame
+                               inFrame:frame];
+  }
+}
+
+#pragma mark - CRWWebStateListObserver
+
+- (void)webStateList:(WebStateList*)webStateList
+    didChangeActiveWebState:(web::WebState*)newWebState
+                oldWebState:(web::WebState*)oldWebState
+                    atIndex:(int)atIndex
+                     reason:(int)reason {
+  self.webState = newWebState;
+}
+
+#pragma mark - Setters
+
+// Sets the new web state and detaches from the previous web state.
+- (void)setWebState:(web::WebState*)webState {
+  if (_webState) {
+    _formActivityObserverBridge.reset();
+  }
+
+  _webState = webState;
+
+  if (_webState) {
+    _formActivityObserverBridge =
+        std::make_unique<autofill::FormActivityObserverBridge>(_webState, self);
+  }
+}
+
+@end
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper_unittest.mm b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper_unittest.mm
new file mode 100644
index 0000000..3d7c609e
--- /dev/null
+++ b/ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper_unittest.mm
@@ -0,0 +1,154 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h"
+
+#import "components/autofill/ios/form_util/form_activity_observer_bridge.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
+#include "components/autofill/ios/form_util/test_form_activity_tab_helper.h"
+#import "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
+#import "ios/chrome/browser/web_state_list/web_state_list.h"
+#import "ios/chrome/browser/web_state_list/web_state_opener.h"
+#import "ios/web/public/test/fakes/test_web_state.h"
+#include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+class ManualFillFormObserverHelperiOSTest : public PlatformTest {
+ public:
+  ManualFillFormObserverHelperiOSTest()
+      : web_state_list_(&web_state_list_delegate_) {}
+
+  ~ManualFillFormObserverHelperiOSTest() override {}
+
+  void SetUp() override {
+    PlatformTest::SetUp();
+    _helper =
+        [[FormObserverHelper alloc] initWithWebStateList:&web_state_list_];
+    _mockDelegate = OCMProtocolMock(@protocol(FormActivityObserver));
+    _helper.delegate = _mockDelegate;
+  }
+
+  void TearDown() override {
+    _helper = nil;
+    _mockDelegate = nil;
+    PlatformTest::TearDown();
+  }
+
+ protected:
+  FakeWebStateListDelegate web_state_list_delegate_;
+  WebStateList web_state_list_;
+  FormObserverHelper* _helper;
+  OCMockObject<FormActivityObserver>* _mockDelegate;
+
+  std::unique_ptr<web::TestWebState> CreateWebState(const char* url) {
+    auto test_web_state = std::make_unique<web::TestWebState>();
+    test_web_state->SetCurrentURL(GURL(url));
+    return test_web_state;
+  }
+
+  void AppendNewWebState(const char* url) {
+    AppendNewWebState(url, WebStateOpener());
+  }
+
+  void AppendNewWebState(const char* url, WebStateOpener opener) {
+    web_state_list_.InsertWebState(WebStateList::kInvalidIndex,
+                                   CreateWebState(url),
+                                   WebStateList::INSERT_NO_FLAGS, opener);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ManualFillFormObserverHelperiOSTest);
+};
+
+// Tests that an observer is correctly created and set up.
+TEST_F(ManualFillFormObserverHelperiOSTest, Creation) {}
+
+// Test that the observer delegates one active web state callbacks.
+TEST_F(ManualFillFormObserverHelperiOSTest, ObservesWebState) {
+  AppendNewWebState("https://example.com");
+  web_state_list_.ActivateWebStateAt(0);
+
+  autofill::FormActivityParams params;
+  params.form_name = "form";
+  params.field_name = "field";
+  params.field_identifier = "field_id";
+  params.field_type = "text";
+  params.type = "blur";
+  params.value = "value";
+  params.input_missing = false;
+
+  OCMExpect([_mockDelegate
+                     webState:static_cast<web::WebState*>([OCMArg anyPointer])
+      didRegisterFormActivity:params
+                      inFrame:static_cast<web::WebFrame*>(
+                                  [OCMArg anyPointer])]);
+
+  autofill::TestFormActivityTabHelper test_form_activity_tab_helper(
+      web_state_list_.GetActiveWebState());
+  test_form_activity_tab_helper.FormActivityRegistered(nullptr, params);
+  @try {
+    [_mockDelegate verify];
+  } @catch (NSException* exception) {
+    ADD_FAILURE();
+  }
+}
+
+// Test that the observer delegates the callbacks with multiple active web
+// state.
+TEST_F(ManualFillFormObserverHelperiOSTest, ObservesMultipleWebStates) {
+  AppendNewWebState("https://example.com");
+  AppendNewWebState("https://chrome.com");
+
+  autofill::TestFormActivityTabHelper test_form_activity_tab_helper0(
+      web_state_list_.GetWebStateAt(0));
+  autofill::TestFormActivityTabHelper test_form_activity_tab_helper1(
+      web_state_list_.GetWebStateAt(1));
+
+  web_state_list_.ActivateWebStateAt(0);
+
+  autofill::FormActivityParams params;
+  params.form_name = "form";
+  params.field_name = "field";
+  params.field_identifier = "field_id";
+  params.field_type = "text";
+  params.type = "focus";
+  params.value = "value";
+  params.input_missing = false;
+
+  @try {
+    OCMExpect([_mockDelegate
+                       webState:static_cast<web::WebState*>([OCMArg anyPointer])
+        didRegisterFormActivity:params
+                        inFrame:static_cast<web::WebFrame*>(
+                                    [OCMArg anyPointer])]);
+
+    test_form_activity_tab_helper0.FormActivityRegistered(nullptr, params);
+    [_mockDelegate verify];
+
+    web_state_list_.ActivateWebStateAt(1);
+
+    OCMExpect([_mockDelegate
+                       webState:static_cast<web::WebState*>([OCMArg anyPointer])
+        didRegisterFormActivity:params
+                        inFrame:static_cast<web::WebFrame*>(
+                                    [OCMArg anyPointer])]);
+    test_form_activity_tab_helper1.FormActivityRegistered(nullptr, params);
+    [_mockDelegate verify];
+
+    web_state_list_.ActivateWebStateAt(0);
+    OCMExpect([_mockDelegate
+                       webState:static_cast<web::WebState*>([OCMArg anyPointer])
+        didRegisterFormActivity:params
+                        inFrame:static_cast<web::WebFrame*>(
+                                    [OCMArg anyPointer])]);
+    test_form_activity_tab_helper0.FormActivityRegistered(nullptr, params);
+    [_mockDelegate verify];
+  } @catch (NSException* exception) {
+    ADD_FAILURE();
+  }
+}
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm
index 791db91..6d1c7e5 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/manual_fill_injection_handler.mm
@@ -6,47 +6,75 @@
 
 #include "base/mac/foundation_util.h"
 #import "components/autofill/ios/browser/js_suggestion_manager.h"
+#import "components/autofill/ios/form_util/form_activity_observer_bridge.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_view_handler.h"
+#import "ios/chrome/browser/ui/autofill/manual_fill/form_observer_helper.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #include "ios/web/public/web_state/web_state.h"
+#include "url/gurl.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-@interface ManualFillInjectionHandler ()
-// The WebStateList with the relevant active web state for the injection.
-@property(nonatomic, assign) WebStateList* webStateList;
+@interface ManualFillInjectionHandler ()<FormActivityObserver>
+// The object in charge of listening to form events and reporting back.
+@property(nonatomic, strong) FormObserverHelper* formHelper;
 // Convenience getter for the current injection reciever.
 @property(nonatomic, readonly) CRWJSInjectionReceiver* injectionReceiver;
 // Convenience getter for the current suggestion manager.
 @property(nonatomic, readonly) JsSuggestionManager* suggestionManager;
+// The WebStateList with the relevant active web state for the injection.
+@property(nonatomic, assign) WebStateList* webStateList;
+// YES if the last focused element is secure within its web frame. To be secure
+// means it has a password type, the web is https and the URL can trusted.
+@property(nonatomic, assign) BOOL lastActiveElementIsSecure;
 @end
 
 @implementation ManualFillInjectionHandler
-
+@synthesize formHelper = _formHelper;
+@synthesize lastActiveElementIsSecure = _lastActiveElementIsSecure;
 @synthesize webStateList = _webStateList;
 
 - (instancetype)initWithWebStateList:(WebStateList*)webStateList {
   self = [super init];
   if (self) {
     _webStateList = webStateList;
+    _formHelper =
+        [[FormObserverHelper alloc] initWithWebStateList:webStateList];
+    _formHelper.delegate = self;
   }
   return self;
 }
-
 #pragma mark - ManualFillViewDelegate
 
 - (void)userDidPickContent:(NSString*)content isSecure:(BOOL)isSecure {
-  if (isSecure) {
-    // TODO:(https://crbug.com/878388) implement secure manual fill for
-    // passwords.
+  if (isSecure && !self.lastActiveElementIsSecure) {
     return;
   }
   [self fillLastSelectedFieldWithString:content];
 }
 
+#pragma mark - FormActivityObserver
+
+- (void)webState:(web::WebState*)webState
+    didRegisterFormActivity:(const autofill::FormActivityParams&)params
+                    inFrame:(web::WebFrame*)frame {
+  if (params.type != "focus") {
+    return;
+  }
+  web::URLVerificationTrustLevel trustLevel;
+  const GURL pageURL(webState->GetCurrentURL(&trustLevel));
+  self.lastActiveElementIsSecure = YES;
+  if (trustLevel != web::URLVerificationTrustLevel::kAbsolute ||
+      !pageURL.SchemeIs(url::kHttpsScheme) || !webState->ContentIsHTML() ||
+      params.field_type != "password") {
+    self.lastActiveElementIsSecure = NO;
+  }
+}
+
 #pragma mark - Getters
 
 - (CRWJSInjectionReceiver*)injectionReceiver {
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h
index b6f2d7b..3f4ca71 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.h
@@ -7,6 +7,7 @@
 
 #import "ios/chrome/browser/ui/coordinators/chrome_coordinator.h"
 
+@class ManualFillInjectionHandler;
 class WebStateList;
 
 // Creates and manages a view controller to present passwords to the user.
@@ -17,12 +18,13 @@
 // The view controller of this coordinator.
 @property(nonatomic, readonly) UIViewController* viewController;
 
-// Creates a coordinator that uses a |viewController| a |browserState| and
-// a |webStateList|.
-- (instancetype)initWithBaseViewController:(UIViewController*)viewController
-                              browserState:
-                                  (ios::ChromeBrowserState*)browserState
-                              webStateList:(WebStateList*)webStateList;
+// Creates a coordinator that uses a |viewController|, |browserState|,
+// |webStateList| and an |injectionHandler|.
+- (instancetype)
+initWithBaseViewController:(UIViewController*)viewController
+              browserState:(ios::ChromeBrowserState*)browserState
+              webStateList:(WebStateList*)webStateList
+          injectionHandler:(ManualFillInjectionHandler*)injectionHandler;
 
 // Unavailable, use -initWithBaseViewController:browserState:webStateList:.
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm
index b40d5d5..ab89d264 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_coordinator.mm
@@ -39,22 +39,22 @@
 @implementation ManualFillPasswordCoordinator
 
 @synthesize allPasswordsViewController = _allPasswordsViewController;
+@synthesize manualFillInjectionHandler = _manualFillInjectionHandler;
 @synthesize passwordMediator = _passwordMediator;
 @synthesize passwordViewController = _passwordViewController;
-@synthesize manualFillInjectionHandler = _manualFillInjectionHandler;
 
-- (instancetype)initWithBaseViewController:(UIViewController*)viewController
-                              browserState:
-                                  (ios::ChromeBrowserState*)browserState
-                              webStateList:(WebStateList*)webStateList {
+- (instancetype)
+initWithBaseViewController:(UIViewController*)viewController
+              browserState:(ios::ChromeBrowserState*)browserState
+              webStateList:(WebStateList*)webStateList
+          injectionHandler:(ManualFillInjectionHandler*)injectionHandler {
   self = [super initWithBaseViewController:viewController
                               browserState:browserState];
   if (self) {
     _passwordViewController =
         [[PasswordViewController alloc] initWithSearchController:nil];
 
-    _manualFillInjectionHandler =
-        [[ManualFillInjectionHandler alloc] initWithWebStateList:webStateList];
+    _manualFillInjectionHandler = injectionHandler;
 
     auto passwordStore = IOSChromePasswordStoreFactory::GetForBrowserState(
         browserState, ServiceAccessType::EXPLICIT_ACCESS);
diff --git a/ios/chrome/browser/ui/bookmarks/BUILD.gn b/ios/chrome/browser/ui/bookmarks/BUILD.gn
index 94b17ba6..f3b50cf 100644
--- a/ios/chrome/browser/ui/bookmarks/BUILD.gn
+++ b/ios/chrome/browser/ui/bookmarks/BUILD.gn
@@ -105,7 +105,6 @@
     "//ios/chrome/browser/ui/image_util",
     "//ios/chrome/browser/ui/keyboard",
     "//ios/chrome/browser/ui/list_model",
-    "//ios/chrome/browser/ui/main:feature_flags",
     "//ios/chrome/browser/ui/material_components",
     "//ios/chrome/browser/ui/ntp",
     "//ios/chrome/browser/ui/signin_interaction/public",
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index af19d18a..6e57b50b 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -162,7 +162,6 @@
 #import "ios/chrome/browser/ui/image_util/image_saver.h"
 #import "ios/chrome/browser/ui/key_commands_provider.h"
 #import "ios/chrome/browser/ui/location_bar_notification_names.h"
-#import "ios/chrome/browser/ui/main/main_feature_flags.h"
 #import "ios/chrome/browser/ui/main_content/main_content_ui.h"
 #import "ios/chrome/browser/ui/main_content/main_content_ui_broadcasting_util.h"
 #import "ios/chrome/browser/ui/main_content/main_content_ui_state.h"
@@ -1442,13 +1441,11 @@
   };
 
   [self setLastTapPointFromCommand:originPoint];
-  // When the tab switcher presentation experiment is enabled, the new tab can
-  // be opened before BVC has been made visible onscreen.  Test for this case by
-  // checking if the parent container VC is currently in the process of being
-  // presented.
+  // The new tab can be opened before BVC has been made visible onscreen.  Test
+  // for this case by checking if the parent container VC is currently in the
+  // process of being presented.
   DCHECK(self.visible || self.dismissingModal ||
-         (TabSwitcherPresentsBVCEnabled() &&
-          self.parentViewController.isBeingPresented));
+         self.parentViewController.isBeingPresented);
 
   // In most cases, we want to take a snapshot of the current tab before opening
   // a new tab. However, if the current tab is not fully visible (did not finish
@@ -1565,7 +1562,7 @@
     //
     // To ensure the completion is called, nil is passed to the call to dismiss,
     // and the completion is called explicitly below.
-    if (!TabSwitcherPresentsBVCEnabled() || !self.dismissingModal) {
+    if (!self.dismissingModal) {
       [self dismissViewControllerAnimated:NO completion:nil];
     }
     // Dismissed controllers will be so after a delay. Queue the completion
@@ -1911,7 +1908,7 @@
 
 - (void)dismissViewControllerAnimated:(BOOL)flag
                            completion:(void (^)())completion {
-  if (TabSwitcherPresentsBVCEnabled() && !self.presentedViewController) {
+  if (!self.presentedViewController) {
     // TODO(crbug.com/801165): On iOS10, UIDocumentMenuViewController and
     // WKFileUploadPanel somehow combine to call dismiss twice instead of once.
     // The second call would dismiss the BVC itself, so look for that case and
@@ -1928,16 +1925,13 @@
   }
 
   // Some calling code invokes |dismissViewControllerAnimated:completion:|
-  // multiple times.  When the BVC is displayed using VC containment, multiple
-  // calls are effectively idempotent because only the first call has any effect
-  // and subsequent calls do nothing.  However, when the BVC is presented,
-  // subsequent calls end up dismissing the BVC itself.  This is never what we
-  // want, so check for this case and return early.  It is not enough to check
+  // multiple times. Because the BVC is presented, subsequent calls end up
+  // dismissing the BVC itself. This is never what should happen, so check for
+  // this case and return early.  It is not enough to check
   // |self.dismissingModal| because some dismissals do not go through
   // -[BrowserViewController dismissViewControllerAnimated:completion:|.
   // TODO(crbug.com/782338): Fix callers and remove this early return.
-  if (TabSwitcherPresentsBVCEnabled() &&
-      (self.dismissingModal || self.presentedViewController.isBeingDismissed)) {
+  if (self.dismissingModal || self.presentedViewController.isBeingDismissed) {
     return;
   }
 
diff --git a/ios/chrome/browser/ui/collection_view/collection_view_controller.mm b/ios/chrome/browser/ui/collection_view/collection_view_controller.mm
index ac2f8f3..f933dd8 100644
--- a/ios/chrome/browser/ui/collection_view/collection_view_controller.mm
+++ b/ios/chrome/browser/ui/collection_view/collection_view_controller.mm
@@ -45,6 +45,12 @@
         self.collectionView;
     // After all other views have been registered.
     [self addChildViewController:_appBarViewController];
+    // Match the width of the parent view.
+    CGRect frame = self.appBarViewController.view.frame;
+    frame.origin.x = 0;
+    frame.size.width =
+        self.appBarViewController.parentViewController.view.bounds.size.width;
+    self.appBarViewController.view.frame = frame;
     [self.view addSubview:self.appBarViewController.view];
     [self.appBarViewController didMoveToParentViewController:self];
   }
diff --git a/ios/chrome/browser/ui/commands/application_commands.h b/ios/chrome/browser/ui/commands/application_commands.h
index 4c82ecf..0d3cd20 100644
--- a/ios/chrome/browser/ui/commands/application_commands.h
+++ b/ios/chrome/browser/ui/commands/application_commands.h
@@ -79,10 +79,6 @@
 // Shows the TabSwitcher UI.
 - (void)displayTabSwitcher;
 
-// Shows the Clear Browsing Data Settings UI (part of Settings).
-- (void)showClearBrowsingDataSettingsFromViewController:
-    (UIViewController*)baseViewController;
-
 // TODO(crbug.com/779791) : Do not pass baseViewController through dispatcher.
 // Shows the Autofill Settings UI, presenting from |baseViewController|.
 - (void)showAutofillSettingsFromViewController:
diff --git a/ios/chrome/browser/ui/first_run/static_file_view_controller.mm b/ios/chrome/browser/ui/first_run/static_file_view_controller.mm
index 25f33a0..e241e306 100644
--- a/ios/chrome/browser/ui/first_run/static_file_view_controller.mm
+++ b/ios/chrome/browser/ui/first_run/static_file_view_controller.mm
@@ -83,6 +83,12 @@
 
   // Add the app bar at the end.
   [self addChildViewController:_appBarViewController];
+  // Match the width of the parent view.
+  CGRect frame = _appBarViewController.view.frame;
+  frame.origin.x = 0;
+  frame.size.width =
+      _appBarViewController.parentViewController.view.bounds.size.width;
+  _appBarViewController.view.frame = frame;
   [self.view addSubview:_appBarViewController.view];
   [_appBarViewController didMoveToParentViewController:self];
 
diff --git a/ios/chrome/browser/ui/history/BUILD.gn b/ios/chrome/browser/ui/history/BUILD.gn
index 5dc33c6..24ca9b3 100644
--- a/ios/chrome/browser/ui/history/BUILD.gn
+++ b/ios/chrome/browser/ui/history/BUILD.gn
@@ -5,80 +5,28 @@
 source_set("history") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
-    "clear_browsing_bar.h",
-    "clear_browsing_bar.mm",
-    "favicon_view.h",
-    "favicon_view.mm",
-    "favicon_view_provider.h",
-    "favicon_view_provider.mm",
     "history_coordinator.h",
     "history_coordinator.mm",
     "history_mediator.h",
     "history_mediator.mm",
-    "history_panel_view_controller.h",
-    "history_panel_view_controller.mm",
-    "history_search_view.h",
-    "history_search_view.mm",
-    "history_search_view_controller.h",
-    "history_search_view_controller.mm",
     "ios_browsing_history_driver.h",
     "ios_browsing_history_driver.mm",
-    "legacy_history_collection_view_controller.h",
-    "legacy_history_collection_view_controller.mm",
-    "legacy_history_entries_status_item.h",
-    "legacy_history_entries_status_item.mm",
-    "legacy_history_entry_item.h",
-    "legacy_history_entry_item.mm",
   ]
   deps = [
     ":clear_browsing_data",
-    ":feature_flags",
     ":history_ui",
     "//base",
-    "//base:i18n",
     "//components/browser_sync",
     "//components/browsing_data/core",
-    "//components/favicon/core",
-    "//components/favicon_base",
     "//components/history/core/browser",
     "//components/keyed_service/core",
-    "//components/prefs",
-    "//components/query_parser",
-    "//components/strings",
-    "//components/sync/protocol",
-    "//components/url_formatter",
-    "//ios/chrome/app/strings",
-    "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/history",
-    "//ios/chrome/browser/metrics:metrics_internal",
-    "//ios/chrome/browser/signin",
     "//ios/chrome/browser/sync",
     "//ios/chrome/browser/ui",
-    "//ios/chrome/browser/ui/collection_view",
-    "//ios/chrome/browser/ui/colors",
-    "//ios/chrome/browser/ui/commands",
-    "//ios/chrome/browser/ui/context_menu",
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
-    "//ios/chrome/browser/ui/icons",
-    "//ios/chrome/browser/ui/keyboard",
-    "//ios/chrome/browser/ui/list_model",
-    "//ios/chrome/browser/ui/material_components",
-    "//ios/chrome/browser/ui/ntp/recent_tabs/views",
-    "//ios/chrome/browser/ui/popup_menu",
-    "//ios/chrome/browser/ui/settings",
     "//ios/chrome/browser/ui/table_view",
-    "//ios/chrome/browser/ui/table_view/cells",
-    "//ios/chrome/browser/ui/util",
-    "//ios/chrome/common",
-    "//ios/third_party/material_components_ios",
-    "//ios/third_party/material_roboto_font_loader_ios",
-    "//ios/web",
-    "//net",
-    "//skia",
-    "//ui/base",
-    "//url",
   ]
   libs = [
     "MobileCoreServices.framework",
@@ -161,80 +109,22 @@
   ]
 }
 
-source_set("feature_flags") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  sources = [
-    "features.cc",
-    "features.h",
-  ]
-  deps = [
-    "//base",
-  ]
-}
-
 source_set("unit_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   sources = [
-    "favicon_view_provider_unittest.mm",
     "history_entry_inserter_unittest.mm",
-    "history_search_view_controller_unittest.mm",
-    "legacy_history_entries_status_item_unittest.mm",
-    "legacy_history_entry_item_unittest.mm",
   ]
   deps = [
-    ":history",
     ":history_ui",
-    ":resources_unit_tests",
     "//base",
     "//base/test:test_support",
-    "//components/browser_sync",
-    "//components/favicon/core",
-    "//components/favicon/core/test:test_support",
-    "//components/favicon_base",
     "//components/history/core/browser",
-    "//components/keyed_service/core",
-    "//components/sessions",
-    "//components/strings",
-    "//ios/chrome/app/strings",
-    "//ios/chrome/browser",
-    "//ios/chrome/browser/browser_state:test_support",
-    "//ios/chrome/browser/history",
-    "//ios/chrome/browser/signin",
-    "//ios/chrome/browser/signin:test_support",
-    "//ios/chrome/browser/sync:sync",
-    "//ios/chrome/browser/sync:test_support",
     "//ios/chrome/browser/ui",
-    "//ios/chrome/browser/ui:feature_flags",
-    "//ios/chrome/browser/ui/collection_view",
     "//ios/chrome/browser/ui/list_model",
-    "//ios/chrome/browser/ui/util",
-    "//ios/chrome/common",
     "//ios/chrome/test:test_support",
-    "//ios/web",
-    "//ios/web/public/test",
-    "//skia",
-    "//testing/gmock",
     "//testing/gtest",
     "//third_party/ocmock",
-    "//ui/base",
-    "//ui/gfx",
-    "//url",
-  ]
-}
-
-bundle_data("resources_unit_tests") {
-  visibility = [
-    ":unit_tests",
-    ":unit_tests_arc",
-  ]
-  testonly = true
-  sources = [
-    "//ios/chrome/test/data/favicon/test_favicon.png",
-  ]
-  outputs = [
-    "{{bundle_resources_dir}}/" +
-        "ios/chrome/test/data/favicon/{{source_file_part}}",
   ]
 }
 
diff --git a/ios/chrome/browser/ui/history/clear_browsing_bar.h b/ios/chrome/browser/ui/history/clear_browsing_bar.h
deleted file mode 100644
index d2bf263f..0000000
--- a/ios/chrome/browser/ui/history/clear_browsing_bar.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_CLEAR_BROWSING_BAR_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_CLEAR_BROWSING_BAR_H_
-
-#import <UIKit/UIKit.h>
-
-// View at the bottom of the history panel that presents options to clear
-// browsing data or enter edit mode. When in edit mode, the bar displays a
-// delete button and a cancel button instead.
-@interface ClearBrowsingBar : UIView
-
-// Yes if in edit mode. Setting to |editing| ClearBrowsingBar for edit
-// mode or non-edit mode accordingly.
-@property(nonatomic, getter=isEditing) BOOL editing;
-// Yes if the edit button is enabled. Setting |editButtonEnabled| enables or
-// disables the edit button accordingly.
-@property(nonatomic, getter=isEditButtonEnabled) BOOL editButtonEnabled;
-// Yes if the delete button is enabled. Setting |deleteButtonEnabled| enables or
-// disables the delete button accordingly.
-@property(nonatomic, getter=isDeleteButtonEnabled) BOOL deleteButtonEnabled;
-
-// Sets the target/action of the "Clear Browsing Data..." button.
-- (void)setClearBrowsingDataTarget:(id)target action:(SEL)action;
-// Sets the target/action of the "Edit" button.
-- (void)setEditTarget:(id)target action:(SEL)action;
-// Sets the target/action of the "Delete" button.
-- (void)setDeleteTarget:(id)taret action:(SEL)action;
-// Sets the target/action of the "Cancel" button.
-- (void)setCancelTarget:(id)target action:(SEL)action;
-// Updates the height of the ClearBrowsingBar.
-- (void)updateHeight;
-
-@end
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_CLEAR_BROWSING_BAR_H_
diff --git a/ios/chrome/browser/ui/history/clear_browsing_bar.mm b/ios/chrome/browser/ui/history/clear_browsing_bar.mm
deleted file mode 100644
index e14ce2b..0000000
--- a/ios/chrome/browser/ui/history/clear_browsing_bar.mm
+++ /dev/null
@@ -1,305 +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.
-
-#import "ios/chrome/browser/ui/history/clear_browsing_bar.h"
-
-#include "base/logging.h"
-#include "components/strings/grit/components_strings.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/browser/ui/history/history_ui_constants.h"
-#include "ios/chrome/browser/ui/rtl_geometry.h"
-#import "ios/chrome/browser/ui/uikit_ui_util.h"
-#import "ios/chrome/common/ui_util/constraints_ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#import "ui/gfx/ios/NSString+CrStringDrawing.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Shadow opacity for the clear browsing bar.
-const CGFloat kShadowOpacity = 0.12f;
-// Shadow radius for the clear browsing bar.
-const CGFloat kShadowRadius = 12.0f;
-// Horizontal margin and spacing for the contents of clear browsing bar.
-const CGFloat kHorizontalMargin = 16.0f;
-// Vertical margin for the contents of clear browsing bar.
-const CGFloat kVerticalMargin = 8.0f;
-// Horizontal spacing between the buttons inside clear browsing bar.
-const CGFloat kHorizontalSpacing = 8.0f;
-// Height of the toolbar in normal state.
-const CGFloat kToolbarNormalHeight = 48.0f;
-// Height of the expanded toolbar (buttons on multiple lines).
-const CGFloat kToolbarExpandedHeight = 58.0f;
-// Maximum proportion of the width of a button in the toolbar.
-const CGFloat kMaxButtonWidthRatio = 0.52f;
-// Enum to specify button position in the clear browsing bar.
-typedef NS_ENUM(BOOL, ButtonPlacement) { Leading, Trailing };
-}  // namespace
-
-@interface ClearBrowsingBar ()
-
-// Button that displays "Clear Browsing Data...".
-@property(nonatomic, strong) UIButton* clearBrowsingDataButton;
-@property(nonatomic, strong) UIView* clearButtonContainer;
-// Button that displays "Edit".
-@property(nonatomic, strong) UIButton* editButton;
-@property(nonatomic, strong) UIView* editButtonContainer;
-// Button that displays "Delete".
-@property(nonatomic, strong) UIButton* deleteButton;
-@property(nonatomic, strong) UIView* deleteButtonContainer;
-// Button that displays "Cancel".
-@property(nonatomic, strong) UIButton* cancelButton;
-@property(nonatomic, strong) UIView* cancelButtonContainer;
-// Stack view for arranging the buttons.
-@property(nonatomic, strong) UIStackView* stackView;
-// Height constraint for the stack view containing the buttons.
-@property(nonatomic, strong) NSLayoutConstraint* heightConstraint;
-
-// Styles button for Leading or Trailing placement. Leading buttons have red
-// text that is aligned to the leading edge. Trailing buttons have blue text
-// that is aligned to the trailing edge.
-- (void)styleButton:(UIButton*)button forPlacement:(ButtonPlacement)placement;
-
-@end
-
-@implementation ClearBrowsingBar
-
-@synthesize editing = _editing;
-@synthesize clearBrowsingDataButton = _clearBrowsingDataButton;
-@synthesize clearButtonContainer = _clearButtonContainer;
-@synthesize editButton = _editButton;
-@synthesize editButtonContainer = _editButtonContainer;
-@synthesize deleteButton = _deleteButton;
-@synthesize deleteButtonContainer = _deleteButtonContainer;
-@synthesize cancelButton = _cancelButton;
-@synthesize cancelButtonContainer = _cancelButtonContainer;
-@synthesize stackView = _stackView;
-@synthesize heightConstraint = _heightConstraint;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    NSDictionary* views = nil;
-    NSArray* constraints = nil;
-
-    _clearBrowsingDataButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    [_clearBrowsingDataButton
-        setTitle:l10n_util::GetNSStringWithFixup(
-                     IDS_HISTORY_OPEN_CLEAR_BROWSING_DATA_DIALOG)
-        forState:UIControlStateNormal];
-    _clearBrowsingDataButton.accessibilityIdentifier =
-        kHistoryToolbarClearBrowsingButtonIdentifier;
-
-    [self styleButton:_clearBrowsingDataButton forPlacement:Leading];
-    _clearButtonContainer = [[UIView alloc] init];
-    [_clearButtonContainer addSubview:_clearBrowsingDataButton];
-    views = @{@"button" : _clearBrowsingDataButton};
-    constraints = @[ @"V:|[button]|", @"H:|[button]" ];
-    ApplyVisualConstraints(constraints, views);
-    [_clearBrowsingDataButton.trailingAnchor
-        constraintLessThanOrEqualToAnchor:_clearButtonContainer.trailingAnchor]
-        .active = YES;
-
-    _editButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    [_editButton
-        setTitle:l10n_util::GetNSString(IDS_HISTORY_START_EDITING_BUTTON)
-        forState:UIControlStateNormal];
-    _editButton.accessibilityIdentifier = kHistoryToolbarEditButtonIdentifier;
-
-    [self styleButton:_editButton forPlacement:Trailing];
-    _editButtonContainer = [[UIView alloc] init];
-    [_editButtonContainer addSubview:_editButton];
-    views = @{@"button" : _editButton};
-    constraints = @[ @"V:|[button]|", @"H:[button]|" ];
-    ApplyVisualConstraints(constraints, views);
-    [_editButton.leadingAnchor
-        constraintGreaterThanOrEqualToAnchor:_editButtonContainer.leadingAnchor]
-        .active = YES;
-
-    _deleteButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    [_deleteButton setTitle:l10n_util::GetNSString(
-                                IDS_HISTORY_DELETE_SELECTED_ENTRIES_BUTTON)
-                   forState:UIControlStateNormal];
-    _deleteButton.accessibilityIdentifier =
-        kHistoryToolbarDeleteButtonIdentifier;
-    [self styleButton:_deleteButton forPlacement:Leading];
-    _deleteButtonContainer = [[UIView alloc] init];
-    [_deleteButtonContainer addSubview:_deleteButton];
-    views = @{@"button" : _deleteButton};
-    constraints = @[ @"V:|[button]|", @"H:|[button]" ];
-    ApplyVisualConstraints(constraints, views);
-    [_deleteButton.trailingAnchor
-        constraintLessThanOrEqualToAnchor:_deleteButtonContainer.trailingAnchor]
-        .active = YES;
-
-    _cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    [_cancelButton
-        setTitle:l10n_util::GetNSString(IDS_HISTORY_CANCEL_EDITING_BUTTON)
-        forState:UIControlStateNormal];
-    _cancelButton.accessibilityIdentifier =
-        kHistoryToolbarCancelButtonIdentifier;
-    [self styleButton:_cancelButton forPlacement:Trailing];
-    _cancelButtonContainer = [[UIView alloc] init];
-    [_cancelButtonContainer addSubview:_cancelButton];
-    views = @{@"button" : _cancelButton};
-    constraints = @[ @"V:|[button]|", @"H:[button]|" ];
-    ApplyVisualConstraints(constraints, views);
-    [_cancelButton.leadingAnchor
-        constraintGreaterThanOrEqualToAnchor:_cancelButtonContainer
-                                                 .leadingAnchor]
-        .active = YES;
-
-    _stackView = [[UIStackView alloc] initWithArrangedSubviews:@[
-      _clearButtonContainer, _editButtonContainer, _deleteButtonContainer,
-      _cancelButtonContainer
-    ]];
-    _stackView.alignment = UIStackViewAlignmentCenter;
-    _stackView.distribution = UIStackViewDistributionEqualSpacing;
-    _stackView.axis = UILayoutConstraintAxisHorizontal;
-
-    [self addSubview:_stackView];
-    _stackView.translatesAutoresizingMaskIntoConstraints = NO;
-
-    PinToSafeArea(_stackView, self);
-    _heightConstraint = [_stackView.heightAnchor
-        constraintEqualToConstant:kToolbarNormalHeight];
-    _heightConstraint.active = YES;
-    _stackView.layoutMarginsRelativeArrangement = YES;
-    _stackView.layoutMargins = UIEdgeInsetsMake(
-        kVerticalMargin, kHorizontalMargin, kVerticalMargin, kHorizontalMargin);
-    _stackView.spacing = kHorizontalSpacing;
-
-    for (UIButton* button in @[
-           _clearBrowsingDataButton, _editButton, _deleteButton, _cancelButton
-         ]) {
-      [button.widthAnchor
-          constraintLessThanOrEqualToAnchor:_stackView.widthAnchor
-                                 multiplier:kMaxButtonWidthRatio]
-          .active = YES;
-    }
-
-    [self setBackgroundColor:[UIColor whiteColor]];
-    [[self layer] setShadowOpacity:kShadowOpacity];
-    [[self layer] setShadowRadius:kShadowRadius];
-    [self setEditing:NO];
-  }
-  return self;
-}
-
-#pragma mark Public Methods
-
-- (void)setEditing:(BOOL)editing {
-  _editing = editing;
-  self.clearButtonContainer.hidden = editing;
-  self.editButtonContainer.hidden = editing;
-  self.deleteButtonContainer.hidden = !editing;
-  self.cancelButtonContainer.hidden = !editing;
-
-  [self updateHeight];
-}
-
-- (BOOL)isEditButtonEnabled {
-  return self.editButton.enabled;
-}
-
-- (void)setEditButtonEnabled:(BOOL)editButtonEnabled {
-  self.editButton.enabled = editButtonEnabled;
-}
-
-- (BOOL)isDeleteButtonEnabled {
-  return self.deleteButton.enabled;
-}
-
-- (void)setDeleteButtonEnabled:(BOOL)deleteButtonEnabled {
-  self.deleteButton.enabled = deleteButtonEnabled;
-}
-
-- (void)setClearBrowsingDataTarget:(id)target action:(SEL)action {
-  [self.clearBrowsingDataButton addTarget:target
-                                   action:action
-                         forControlEvents:UIControlEventTouchUpInside];
-}
-
-- (void)setEditTarget:(id)target action:(SEL)action {
-  [self.editButton addTarget:target
-                      action:action
-            forControlEvents:UIControlEventTouchUpInside];
-}
-
-- (void)setDeleteTarget:(id)target action:(SEL)action {
-  [self.deleteButton addTarget:target
-                        action:action
-              forControlEvents:UIControlEventTouchUpInside];
-}
-
-- (void)setCancelTarget:(id)target action:(SEL)action {
-  [self.cancelButton addTarget:target
-                        action:action
-              forControlEvents:UIControlEventTouchUpInside];
-}
-
-- (void)updateHeight {
-  NSArray* buttons =
-      @[ _clearBrowsingDataButton, _editButton, _deleteButton, _cancelButton ];
-
-  CGFloat buttonMaxWidth = self.frame.size.width * kMaxButtonWidthRatio;
-  CGFloat availableWidth = self.frame.size.width - kHorizontalMargin * 2;
-  NSUInteger visibleCount = 0;
-
-  // Count the number of visible buttons and deduct the button spacings from
-  // availableWidth.
-  for (UIButton* button in buttons) {
-    if (!button.superview.hidden) {
-      visibleCount++;
-      if (visibleCount > 1) {
-        availableWidth -= kHorizontalSpacing;
-      }
-    }
-  }
-
-  // Expand toolbar height in case word wrapping happens.
-  for (UIButton* button in buttons) {
-    if (!button.superview.hidden) {
-      CGFloat rect = [button.titleLabel.text
-                         cr_pixelAlignedSizeWithFont:button.titleLabel.font]
-                         .width;
-      if (rect > availableWidth || rect > buttonMaxWidth) {
-        self.heightConstraint.constant = kToolbarExpandedHeight;
-        return;
-      }
-      availableWidth -= rect;
-    }
-  }
-
-  // Use the normal height when there is no word wrapping.
-  self.heightConstraint.constant = kToolbarNormalHeight;
-}
-
-#pragma mark Private Methods
-
-- (void)styleButton:(UIButton*)button forPlacement:(ButtonPlacement)placement {
-  BOOL leading = placement == Leading;
-  BOOL alignmentLeft = leading ^ UseRTLLayout();
-  [button setBackgroundColor:[UIColor whiteColor]];
-  UIColor* textColor = leading ? [[MDCPalette cr_redPalette] tint500]
-                               : [[MDCPalette cr_bluePalette] tint500];
-  [button setTitleColor:textColor forState:UIControlStateNormal];
-  [button setTitleColor:[[MDCPalette greyPalette] tint500]
-               forState:UIControlStateDisabled];
-  [[button titleLabel] setFont:[MDCTypography subheadFont]];
-  button.titleLabel.textAlignment =
-      alignmentLeft ? NSTextAlignmentLeft : NSTextAlignmentRight;
-  button.contentHorizontalAlignment =
-      alignmentLeft ? UIControlContentHorizontalAlignmentLeft
-                    : UIControlContentHorizontalAlignmentRight;
-  [button setTranslatesAutoresizingMaskIntoConstraints:NO];
-  button.titleLabel.numberOfLines = 2;
-  button.titleLabel.adjustsFontSizeToFitWidth = YES;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/history/favicon_view.h b/ios/chrome/browser/ui/history/favicon_view.h
deleted file mode 100644
index 3a0ce2e..0000000
--- a/ios/chrome/browser/ui/history/favicon_view.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_H_
-
-#import <UIKit/UIKit.h>
-
-// View for displaying the favicon of a history entry.
-@interface FaviconView : UIView
-
-// Size for the favicon.
-@property(nonatomic) CGFloat size;
-// Image view for the favicon.
-@property(nonatomic, strong) UIImageView* faviconImage;
-// Label for fallback favicon placeholder.
-@property(nonatomic, strong) UILabel* faviconFallbackLabel;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_H_
diff --git a/ios/chrome/browser/ui/history/favicon_view.mm b/ios/chrome/browser/ui/history/favicon_view.mm
deleted file mode 100644
index 2b0288b..0000000
--- a/ios/chrome/browser/ui/history/favicon_view.mm
+++ /dev/null
@@ -1,69 +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.
-
-#import "ios/chrome/browser/ui/history/favicon_view.h"
-
-#import "ios/chrome/common/ui_util/constraints_ui_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Default corner radius for the favicon image view.
-const CGFloat kDefaultCornerRadius = 3;
-}
-
-@interface FaviconView () {
-  // Property releaser for FaviconView.
-}
-// Size constraints for the favicon views.
-@property(nonatomic, copy) NSArray* faviconSizeConstraints;
-@end
-
-@implementation FaviconView
-
-@synthesize size = _size;
-@synthesize faviconImage = _faviconImage;
-@synthesize faviconFallbackLabel = _faviconFallbackLabel;
-@synthesize faviconSizeConstraints = _faviconSizeConstraints;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    _faviconImage = [[UIImageView alloc] init];
-    _faviconImage.clipsToBounds = YES;
-    _faviconImage.layer.cornerRadius = kDefaultCornerRadius;
-    _faviconImage.image = nil;
-
-    _faviconFallbackLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    _faviconFallbackLabel.backgroundColor = [UIColor clearColor];
-    _faviconFallbackLabel.textAlignment = NSTextAlignmentCenter;
-    _faviconFallbackLabel.isAccessibilityElement = NO;
-    _faviconFallbackLabel.text = nil;
-
-    [self addSubview:_faviconImage];
-    [self addSubview:_faviconFallbackLabel];
-
-    [_faviconImage setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [_faviconFallbackLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
-    AddSameConstraints(_faviconImage, self);
-    AddSameConstraints(_faviconFallbackLabel, self);
-    _faviconSizeConstraints = @[
-      [self.widthAnchor constraintEqualToConstant:0],
-      [self.heightAnchor constraintEqualToConstant:0],
-    ];
-    [NSLayoutConstraint activateConstraints:_faviconSizeConstraints];
-  }
-  return self;
-}
-
-- (void)setSize:(CGFloat)size {
-  _size = size;
-  for (NSLayoutConstraint* constraint in self.faviconSizeConstraints) {
-    constraint.constant = size;
-  }
-}
-
-@end
diff --git a/ios/chrome/browser/ui/history/favicon_view_provider.h b/ios/chrome/browser/ui/history/favicon_view_provider.h
deleted file mode 100644
index 83c70b0..0000000
--- a/ios/chrome/browser/ui/history/favicon_view_provider.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_PROVIDER_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_PROVIDER_H_
-
-#import <UIKit/UIKit.h>
-
-namespace favicon {
-class LargeIconService;
-}  // namespace favicon
-
-@class FaviconView;
-@class FaviconViewProvider;
-class GURL;
-
-// Delegate protocol for FaviconViewProvider.
-@protocol FaviconViewProviderDelegate<NSObject>
-// Called when favicon or fallback format has been fetched.
-- (void)faviconViewProviderFaviconDidLoad:(FaviconViewProvider*)provider;
-@end
-
-// Object to fetch and configure the view for a favicon, or a fallback icon if
-// there is no favicon image available with large enough resolution.
-@interface FaviconViewProvider : NSObject
-// A favicon or fallback format associated with |URL| will be fetched using
-// |largeIconService|. The favicon will be rendered with height and width equal
-// to |faviconSize|, and the image will be fetched if the source size is greater
-// than or equal to |minFaviconSize|. The |delegate| is notified when the
-// favicon has been loaded, and may be nil.
-- (instancetype)initWithURL:(const GURL&)URL
-                faviconSize:(CGFloat)faviconSize
-             minFaviconSize:(CGFloat)minFaviconSize
-           largeIconService:(favicon::LargeIconService*)largeIconService
-                   delegate:(id<FaviconViewProviderDelegate>)delegate
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)init NS_UNAVAILABLE;
-
-// View that displays a favicon or fallback icon.
-@property(strong, nonatomic, readonly) FaviconView* faviconView;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_FAVICON_VIEW_PROVIDER_H_
diff --git a/ios/chrome/browser/ui/history/favicon_view_provider.mm b/ios/chrome/browser/ui/history/favicon_view_provider.mm
deleted file mode 100644
index 444cda4..0000000
--- a/ios/chrome/browser/ui/history/favicon_view_provider.mm
+++ /dev/null
@@ -1,155 +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.
-
-#import "ios/chrome/browser/ui/history/favicon_view_provider.h"
-
-#include "base/bind.h"
-#include "base/i18n/case_conversion.h"
-#import "base/mac/foundation_util.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/task/cancelable_task_tracker.h"
-#include "components/favicon/core/fallback_url_util.h"
-#include "components/favicon/core/large_icon_service.h"
-#include "components/favicon_base/fallback_icon_style.h"
-#include "components/favicon_base/favicon_types.h"
-#import "ios/chrome/browser/ui/history/favicon_view.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
-#include "skia/ext/skia_utils_ios.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface FaviconViewProvider () {
-  // Delegate for handling completion of favicon load.
-  __weak id<FaviconViewProviderDelegate> _delegate;
-  // Used to cancel tasks for the LargeIconService.
-  base::CancelableTaskTracker _faviconTaskTracker;
-}
-
-// Size to render the favicon.
-@property(nonatomic, assign) CGFloat faviconSize;
-// Favicon image for the favicon view.
-@property(nonatomic, strong) UIImage* favicon;
-// Fallback text for the favicon view if there is no appropriately sized
-// favicon availabile.
-@property(nonatomic, copy) NSString* fallbackText;
-// Fallback background color for the favicon view if there is no appropriately
-// sized favicon available.
-@property(nonatomic, strong) UIColor* fallbackBackgroundColor;
-// Fallback text color for the favicon view if there is no appropriately
-// sized favicon available.
-@property(nonatomic, strong) UIColor* fallbackTextColor;
-
-// Fetches favicon for |URL| from |faviconService|. Notifies delegate when
-// favicon is retrieved.
-- (void)fetchFaviconForURL:(const GURL&)URL
-                      size:(CGFloat)size
-                   minSize:(CGFloat)minSize
-                   service:(favicon::LargeIconService*)faviconService;
-
-@end
-
-@implementation FaviconViewProvider
-
-@synthesize faviconSize = _faviconSize;
-@synthesize favicon = _favicon;
-@synthesize fallbackText = _fallbackText;
-@synthesize fallbackBackgroundColor = _fallbackBackgroundColor;
-@synthesize fallbackTextColor = _fallbackTextColor;
-@synthesize faviconView = _faviconView;
-
-- (instancetype)initWithURL:(const GURL&)URL
-                faviconSize:(CGFloat)faviconSize
-             minFaviconSize:(CGFloat)minFaviconSize
-           largeIconService:(favicon::LargeIconService*)largeIconService
-                   delegate:(id<FaviconViewProviderDelegate>)delegate {
-  self = [super init];
-  if (self) {
-    _faviconSize = faviconSize;
-    _delegate = delegate;
-    _fallbackBackgroundColor = [UIColor grayColor];
-    _fallbackTextColor = [UIColor whiteColor];
-    [self fetchFaviconForURL:URL
-                        size:faviconSize
-                     minSize:minFaviconSize
-                     service:largeIconService];
-  }
-  return self;
-}
-
-- (instancetype)init {
-  NOTREACHED();
-  return nil;
-}
-
-- (void)fetchFaviconForURL:(const GURL&)URL
-                      size:(CGFloat)size
-                   minSize:(CGFloat)minSize
-                   service:(favicon::LargeIconService*)largeIconService {
-  if (!largeIconService)
-    return;
-  __weak FaviconViewProvider* weakSelf = self;
-  GURL blockURL(URL);
-  void (^faviconBlock)(const favicon_base::LargeIconResult&) = ^(
-      const favicon_base::LargeIconResult& result) {
-    FaviconViewProvider* strongSelf = weakSelf;
-    if (!strongSelf)
-      return;
-    if (result.bitmap.is_valid()) {
-      scoped_refptr<base::RefCountedMemory> data =
-          result.bitmap.bitmap_data.get();
-      [strongSelf
-          setFavicon:[UIImage
-                         imageWithData:[NSData dataWithBytes:data->front()
-                                                      length:data->size()]]];
-    } else if (result.fallback_icon_style) {
-      [strongSelf setFallbackBackgroundColor:skia::UIColorFromSkColor(
-                                                 result.fallback_icon_style
-                                                     ->background_color)];
-      [strongSelf
-          setFallbackTextColor:skia::UIColorFromSkColor(
-                                   result.fallback_icon_style->text_color)];
-      [strongSelf setFallbackText:base::SysUTF16ToNSString(
-                                      favicon::GetFallbackIconText(blockURL))];
-    }
-    [strongSelf->_delegate faviconViewProviderFaviconDidLoad:strongSelf];
-  };
-
-  // Always call LargeIconService in case the favicon was updated.
-  CGFloat faviconSize = [UIScreen mainScreen].scale * size;
-  CGFloat minFaviconSize = [UIScreen mainScreen].scale * minSize;
-  largeIconService->GetLargeIconOrFallbackStyle(
-      URL, minFaviconSize, faviconSize, base::BindRepeating(faviconBlock),
-      &_faviconTaskTracker);
-}
-
-- (FaviconView*)faviconView {
-  if (!_faviconView) {
-    _faviconView = [[FaviconView alloc] initWithFrame:CGRectZero];
-  }
-  _faviconView.size = _faviconSize;
-  // Update favicon view with current properties.
-  if (self.favicon) {
-    _faviconView.faviconImage.image = self.favicon;
-    _faviconView.faviconImage.backgroundColor = [UIColor whiteColor];
-    _faviconView.faviconFallbackLabel.text = nil;
-  } else {
-    _faviconView.faviconImage.image = nil;
-    _faviconView.faviconImage.backgroundColor = self.fallbackBackgroundColor;
-    _faviconView.faviconFallbackLabel.text = self.fallbackText;
-    _faviconView.faviconFallbackLabel.textColor = self.fallbackTextColor;
-
-    CGFloat fontSize = floorf(_faviconSize / 2);
-    _faviconView.faviconFallbackLabel.font =
-        [[MDCTypography fontLoader] regularFontOfSize:fontSize];
-  }
-  return _faviconView;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/history/favicon_view_provider_unittest.mm b/ios/chrome/browser/ui/history/favicon_view_provider_unittest.mm
deleted file mode 100644
index e745e03d..0000000
--- a/ios/chrome/browser/ui/history/favicon_view_provider_unittest.mm
+++ /dev/null
@@ -1,154 +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.
-
-#import "ios/chrome/browser/ui/history/favicon_view_provider.h"
-
-#include <memory>
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/location.h"
-#include "base/path_service.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/task/cancelable_task_tracker.h"
-#include "components/favicon/core/large_icon_service.h"
-#include "components/favicon/core/test/mock_favicon_service.h"
-#include "components/favicon_base/fallback_icon_style.h"
-#include "components/favicon_base/favicon_types.h"
-#include "ios/chrome/browser/chrome_paths.h"
-#include "ios/web/public/test/test_web_thread.h"
-#include "ios/web/public/test/test_web_thread_bundle.h"
-#include "skia/ext/skia_utils_ios.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#include "third_party/ocmock/OCMock/OCMock.h"
-#include "third_party/ocmock/gtest_support.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface FaviconViewProvider (Testing)
-@property(nonatomic, retain) UIImage* favicon;
-@property(nonatomic, copy) NSString* fallbackText;
-@property(nonatomic, retain) UIColor* fallbackBackgroundColor;
-@property(nonatomic, retain) UIColor* fallbackTextColor;
-@end
-
-namespace {
-
-using favicon::PostReply;
-using testing::_;
-
-// Dummy URL for the favicon case.
-const char kTestFaviconURL[] = "http://test/favicon";
-// Dummy URL for the fallback case.
-const char kTestFallbackURL[] = "http://test/fallback";
-// Dummy icon URL.
-const char kTestFaviconIconURL[] = "http://test/icons/favicon";
-
-// Size of dummy favicon image.
-const CGFloat kTestFaviconSize = 57;
-
-favicon_base::FaviconRawBitmapResult CreateTestBitmap() {
-  favicon_base::FaviconRawBitmapResult result;
-  result.expired = false;
-  base::FilePath favicon_path;
-  base::PathService::Get(ios::DIR_TEST_DATA, &favicon_path);
-  favicon_path =
-      favicon_path.Append(FILE_PATH_LITERAL("favicon/test_favicon.png"));
-  NSData* favicon_data = [NSData
-      dataWithContentsOfFile:base::SysUTF8ToNSString(favicon_path.value())];
-  scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes(
-      static_cast<const unsigned char*>([favicon_data bytes]),
-      [favicon_data length]));
-
-  result.bitmap_data = data;
-  CGFloat scaled_size = [UIScreen mainScreen].scale * kTestFaviconSize;
-  result.pixel_size = gfx::Size(scaled_size, scaled_size);
-  result.icon_url = GURL(kTestFaviconIconURL);
-  result.icon_type = favicon_base::IconType::kTouchIcon;
-  CHECK(result.is_valid());
-  return result;
-}
-
-class FaviconViewProviderTest : public PlatformTest {
- protected:
-  void SetUp() override {
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-    PlatformTest::SetUp();
-    large_icon_service_.reset(new favicon::LargeIconService(
-        &mock_favicon_service_, /*image_fetcher=*/nullptr));
-
-    EXPECT_CALL(mock_favicon_service_, GetLargestRawFaviconForPageURL(
-                                           GURL(kTestFaviconURL), _, _, _, _))
-        .WillRepeatedly(PostReply<5>(CreateTestBitmap()));
-  }
-
-  web::TestWebThreadBundle thread_bundle_;
-  testing::StrictMock<favicon::MockFaviconService> mock_favicon_service_;
-  std::unique_ptr<favicon::LargeIconService> large_icon_service_;
-  base::CancelableTaskTracker cancelable_task_tracker_;
-};
-
-// Tests that image is set when a favicon is returned from LargeIconService.
-TEST_F(FaviconViewProviderTest, Favicon) {
-  id mock_delegate =
-      [OCMockObject mockForProtocol:@protocol(FaviconViewProviderDelegate)];
-  FaviconViewProvider* viewProvider =
-      [[FaviconViewProvider alloc] initWithURL:GURL(kTestFaviconURL)
-                                   faviconSize:kTestFaviconSize
-                                minFaviconSize:kTestFaviconSize
-                              largeIconService:large_icon_service_.get()
-                                      delegate:mock_delegate];
-  void (^confirmationBlock)(NSInvocation*) = ^(NSInvocation* invocation) {
-    __unsafe_unretained FaviconViewProvider* viewProvider;
-    [invocation getArgument:&viewProvider atIndex:2];
-    EXPECT_NSNE(nil, viewProvider.favicon);
-  };
-  [[[mock_delegate stub] andDo:confirmationBlock]
-      faviconViewProviderFaviconDidLoad:viewProvider];
-  EXPECT_OCMOCK_VERIFY(mock_delegate);
-}
-
-// Tests that fallback data is set when no favicon is returned from
-// LargeIconService.
-TEST_F(FaviconViewProviderTest, FallbackIcon) {
-  EXPECT_CALL(mock_favicon_service_, GetLargestRawFaviconForPageURL(
-                                         GURL(kTestFallbackURL), _, _, _, _))
-      .WillRepeatedly(PostReply<5>(favicon_base::FaviconRawBitmapResult()));
-
-  id mock_delegate =
-      [OCMockObject mockForProtocol:@protocol(FaviconViewProviderDelegate)];
-  FaviconViewProvider* item =
-      [[FaviconViewProvider alloc] initWithURL:GURL(kTestFallbackURL)
-                                   faviconSize:kTestFaviconSize
-                                minFaviconSize:kTestFaviconSize
-                              largeIconService:large_icon_service_.get()
-                                      delegate:mock_delegate];
-
-  // Confirm that fallback text and color have been set before delegate call.
-  void (^confirmationBlock)(NSInvocation*) = ^(NSInvocation* invocation) {
-    __unsafe_unretained FaviconViewProvider* viewProvider;
-    [invocation getArgument:&viewProvider atIndex:2];
-    // Fallback text is the first letter of the URL.
-    NSString* defaultText = @"T";
-    // Default colors are defined in
-    // components/favicon_base/fallback_icon_style.h.
-    UIColor* defaultTextColor = skia::UIColorFromSkColor(SK_ColorWHITE);
-    UIColor* defaultBackgroundColor =
-        skia::UIColorFromSkColor(SkColorSetRGB(0x78, 0x78, 0x78));
-    EXPECT_NSEQ(defaultText, viewProvider.fallbackText);
-    EXPECT_NSEQ(defaultTextColor, viewProvider.fallbackTextColor);
-    EXPECT_NSEQ(defaultBackgroundColor, viewProvider.fallbackBackgroundColor);
-  };
-  [[[mock_delegate stub] andDo:confirmationBlock]
-      faviconViewProviderFaviconDidLoad:item];
-  EXPECT_OCMOCK_VERIFY(mock_delegate);
-}
-
-}  // namespace
diff --git a/ios/chrome/browser/ui/history/features.cc b/ios/chrome/browser/ui/history/features.cc
deleted file mode 100644
index 3e66cc0..0000000
--- a/ios/chrome/browser/ui/history/features.cc
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/history/features.h"
-
-const base::Feature kHistoryBatchUpdatesFilter{
-    "HistoryBatchUpdatesFilter", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/ios/chrome/browser/ui/history/features.h b/ios/chrome/browser/ui/history/features.h
deleted file mode 100644
index 902b0e4..0000000
--- a/ios/chrome/browser/ui/history/features.h
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_FEATURES_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_FEATURES_H_
-
-#include "base/feature_list.h"
-
-// Feature to choose wether history filtering will use one BatchUpdates block.
-extern const base::Feature kHistoryBatchUpdatesFilter;
-
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_FEATURES_H_
diff --git a/ios/chrome/browser/ui/history/history_coordinator.mm b/ios/chrome/browser/ui/history/history_coordinator.mm
index 423e625b..59b0548 100644
--- a/ios/chrome/browser/ui/history/history_coordinator.mm
+++ b/ios/chrome/browser/ui/history/history_coordinator.mm
@@ -7,10 +7,8 @@
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/history/core/browser/browsing_history_service.h"
 #include "components/keyed_service/core/service_access_type.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
-#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/history/history_clear_browsing_data_coordinator.h"
 #include "ios/chrome/browser/ui/history/history_local_commands.h"
 #import "ios/chrome/browser/ui/history/history_mediator.h"
@@ -132,7 +130,6 @@
 }
 
 - (void)displayPrivacySettings {
-  if (IsUIRefreshPhase1Enabled()) {
     self.historyClearBrowsingDataCoordinator =
         [[HistoryClearBrowsingDataCoordinator alloc]
             initWithBaseViewController:self.historyNavigationController
@@ -143,10 +140,6 @@
     self.historyClearBrowsingDataCoordinator.loader = self.loader;
     self.historyClearBrowsingDataCoordinator.dispatcher = self.dispatcher;
     [self.historyClearBrowsingDataCoordinator start];
-  } else {
-    [self.dispatcher showClearBrowsingDataSettingsFromViewController:
-                         self.historyNavigationController];
-  }
 }
 
 @end
diff --git a/ios/chrome/browser/ui/history/history_entry_inserter.mm b/ios/chrome/browser/ui/history/history_entry_inserter.mm
index 8ef149ef..e65882f 100644
--- a/ios/chrome/browser/ui/history/history_entry_inserter.mm
+++ b/ios/chrome/browser/ui/history/history_entry_inserter.mm
@@ -129,20 +129,13 @@
   NSInteger insertionIndex = _firstSectionIndex + index;
   [_listModel insertSectionWithIdentifier:sectionIdentifier
                                   atIndex:insertionIndex];
-  if (IsUIRefreshPhase1Enabled()) {
+
     TableViewTextHeaderFooterItem* header =
         [[TableViewTextHeaderFooterItem alloc] initWithType:kItemTypeEnumZero];
     header.text =
         base::SysUTF16ToNSString(history::GetRelativeDateLocalized(timestamp));
     [_listModel setHeader:header forSectionWithIdentifier:sectionIdentifier];
 
-  } else {
-    CollectionViewTextItem* header =
-        [[CollectionViewTextItem alloc] initWithType:kItemTypeEnumZero];
-    header.text =
-        base::SysUTF16ToNSString(history::GetRelativeDateLocalized(timestamp));
-    [_listModel setHeader:header forSectionWithIdentifier:sectionIdentifier];
-  }
   [self.delegate historyEntryInserter:self
               didInsertSectionAtIndex:insertionIndex];
   return sectionIdentifier;
diff --git a/ios/chrome/browser/ui/history/history_entry_inserter_unittest.mm b/ios/chrome/browser/ui/history/history_entry_inserter_unittest.mm
index 4f2db2c..b6f431b 100644
--- a/ios/chrome/browser/ui/history/history_entry_inserter_unittest.mm
+++ b/ios/chrome/browser/ui/history/history_entry_inserter_unittest.mm
@@ -4,11 +4,14 @@
 
 #import "ios/chrome/browser/ui/history/history_entry_inserter.h"
 
+#include "base/i18n/time_formatting.h"
 #import "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "components/history/core/browser/browsing_history_service.h"
-#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h"
+#import "ios/chrome/browser/ui/history/history_entry_item.h"
+#include "ios/chrome/browser/ui/history/history_util.h"
 #import "ios/chrome/browser/ui/list_model/list_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
@@ -22,16 +25,23 @@
 
 using history::BrowsingHistoryService;
 
-LegacyHistoryEntryItem* TestHistoryEntryItem(base::Time timestamp,
-                                             const std::string& name) {
+HistoryEntryItem* TestHistoryEntryItem(base::Time timestamp,
+                                       const std::string& name) {
   BrowsingHistoryService::HistoryEntry entry(
       BrowsingHistoryService::HistoryEntry::LOCAL_ENTRY,
       GURL(("http://" + name).c_str()), base::UTF8ToUTF16(name.c_str()),
       timestamp, std::string(), false, base::string16(), false);
-  return [[LegacyHistoryEntryItem alloc] initWithType:kItemTypeEnumZero
-                                         historyEntry:entry
-                                         browserState:nil
-                                             delegate:nil];
+  HistoryEntryItem* item =
+      [[HistoryEntryItem alloc] initWithType:kItemTypeEnumZero
+                       accessibilityDelegate:nil];
+  item.text = [history::FormattedTitle(entry.title, entry.url) copy];
+  item.detailText =
+      [base::SysUTF8ToNSString(entry.url.GetOrigin().spec()) copy];
+  item.timeText =
+      [base::SysUTF16ToNSString(base::TimeFormatTimeOfDay(entry.time)) copy];
+  item.URL = entry.url;
+  item.timestamp = entry.time;
+  return item;
 }
 
 // Test fixture for HistoryEntryInserter.
@@ -58,10 +68,9 @@
   base::Time today =
       base::Time::Now().LocalMidnight() + base::TimeDelta::FromHours(1);
   base::TimeDelta minute = base::TimeDelta::FromMinutes(1);
-  LegacyHistoryEntryItem* entry1 = TestHistoryEntryItem(today, "entry1");
-  LegacyHistoryEntryItem* entry2 =
-      TestHistoryEntryItem(today - minute, "entry2");
-  LegacyHistoryEntryItem* entry3 =
+  HistoryEntryItem* entry1 = TestHistoryEntryItem(today, "entry1");
+  HistoryEntryItem* entry2 = TestHistoryEntryItem(today - minute, "entry2");
+  HistoryEntryItem* entry3 =
       TestHistoryEntryItem(today - 2 * (minute), "entry3");
 
   OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_;
@@ -89,8 +98,8 @@
   EXPECT_EQ(0, [model_ numberOfItemsInSection:0]);
   EXPECT_EQ(3, [model_ numberOfItemsInSection:1]);
 
-  NSArray<LegacyHistoryEntryItem*>* section_1 =
-      base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  NSArray<HistoryEntryItem*>* section_1 =
+      base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
           [model_ itemsInSectionWithIdentifier:kSectionIdentifierEnumZero + 1]);
   EXPECT_NSEQ(@"entry1", section_1[0].text);
   EXPECT_NSEQ(@"entry2", section_1[1].text);
@@ -105,12 +114,12 @@
       base::Time::Now().LocalMidnight() + base::TimeDelta::FromHours(12);
   base::TimeDelta day = base::TimeDelta::FromDays(1);
   base::TimeDelta minute = base::TimeDelta::FromMinutes(1);
-  LegacyHistoryEntryItem* day1 = TestHistoryEntryItem(today, "day1");
-  LegacyHistoryEntryItem* day2_entry1 =
+  HistoryEntryItem* day1 = TestHistoryEntryItem(today, "day1");
+  HistoryEntryItem* day2_entry1 =
       TestHistoryEntryItem(today - day, "day2_entry1");
-  LegacyHistoryEntryItem* day2_entry2 =
+  HistoryEntryItem* day2_entry2 =
       TestHistoryEntryItem(today - day - minute, "day2_entry2");
-  LegacyHistoryEntryItem* day3 = TestHistoryEntryItem(today - 2 * day, "day3");
+  HistoryEntryItem* day3 = TestHistoryEntryItem(today - 2 * day, "day3");
 
   OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_;
 
@@ -124,8 +133,8 @@
   EXPECT_EQ(2, [model_ numberOfSections]);
   EXPECT_EQ(0, [model_ numberOfItemsInSection:0]);
   EXPECT_EQ(1, [model_ numberOfItemsInSection:1]);
-  NSArray<LegacyHistoryEntryItem*>* section_1 =
-      base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  NSArray<HistoryEntryItem*>* section_1 =
+      base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
           [model_ itemsInSectionWithIdentifier:day2_identifier]);
   EXPECT_NSEQ(@"day2_entry2", section_1[0].text);
   EXPECT_OCMOCK_VERIFY(mock_delegate);
@@ -141,11 +150,11 @@
   EXPECT_EQ(0, [model_ numberOfItemsInSection:0]);
   EXPECT_EQ(1, [model_ numberOfItemsInSection:1]);
   EXPECT_EQ(1, [model_ numberOfItemsInSection:2]);
-  section_1 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  section_1 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
       [model_ itemsInSectionWithIdentifier:day1_identifier]);
   EXPECT_NSEQ(@"day1", section_1[0].text);
-  NSArray<LegacyHistoryEntryItem*>* section_2 =
-      base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  NSArray<HistoryEntryItem*>* section_2 =
+      base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
           [model_ itemsInSectionWithIdentifier:day2_identifier]);
   EXPECT_NSEQ(@"day2_entry2", section_2[0].text);
   EXPECT_OCMOCK_VERIFY(mock_delegate);
@@ -162,14 +171,14 @@
   EXPECT_EQ(1, [model_ numberOfItemsInSection:1]);
   EXPECT_EQ(1, [model_ numberOfItemsInSection:2]);
   EXPECT_EQ(1, [model_ numberOfItemsInSection:3]);
-  section_1 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  section_1 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
       [model_ itemsInSectionWithIdentifier:day1_identifier]);
   EXPECT_NSEQ(@"day1", section_1[0].text);
-  section_2 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  section_2 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
       [model_ itemsInSectionWithIdentifier:day2_identifier]);
   EXPECT_NSEQ(@"day2_entry2", section_2[0].text);
-  NSArray<LegacyHistoryEntryItem*>* section_3 =
-      base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  NSArray<HistoryEntryItem*>* section_3 =
+      base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
           [model_ itemsInSectionWithIdentifier:day3_identifier]);
   EXPECT_NSEQ(@"day3", section_3[0].text);
   EXPECT_OCMOCK_VERIFY(mock_delegate);
@@ -183,14 +192,14 @@
   EXPECT_EQ(1, [model_ numberOfItemsInSection:1]);
   EXPECT_EQ(2, [model_ numberOfItemsInSection:2]);
   EXPECT_EQ(1, [model_ numberOfItemsInSection:3]);
-  section_1 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  section_1 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
       [model_ itemsInSectionWithIdentifier:day1_identifier]);
   EXPECT_NSEQ(@"day1", section_1[0].text);
-  section_2 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  section_2 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
       [model_ itemsInSectionWithIdentifier:day2_identifier]);
   EXPECT_NSEQ(@"day2_entry1", section_2[0].text);
   EXPECT_NSEQ(@"day2_entry2", section_2[1].text);
-  section_3 = base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  section_3 = base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
       [model_ itemsInSectionWithIdentifier:day3_identifier]);
   EXPECT_NSEQ(@"day3", section_3[0].text);
   EXPECT_OCMOCK_VERIFY(mock_delegate);
@@ -199,8 +208,8 @@
 // Tests that items are only ever added once.
 TEST_F(HistoryEntryInserterTest, AddDuplicateItems) {
   base::Time today = base::Time::Now();
-  LegacyHistoryEntryItem* entry1 = TestHistoryEntryItem(today, "entry");
-  LegacyHistoryEntryItem* entry2 = TestHistoryEntryItem(today, "entry");
+  HistoryEntryItem* entry1 = TestHistoryEntryItem(today, "entry");
+  HistoryEntryItem* entry2 = TestHistoryEntryItem(today, "entry");
 
   OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_;
   [[mock_delegate expect] historyEntryInserter:inserter_
@@ -215,8 +224,8 @@
   EXPECT_EQ(0, [model_ numberOfItemsInSection:0]);
   EXPECT_EQ(1, [model_ numberOfItemsInSection:1]);
 
-  NSArray<LegacyHistoryEntryItem*>* section_1 =
-      base::mac::ObjCCastStrict<NSArray<LegacyHistoryEntryItem*>>(
+  NSArray<HistoryEntryItem*>* section_1 =
+      base::mac::ObjCCastStrict<NSArray<HistoryEntryItem*>>(
           [model_ itemsInSectionWithIdentifier:kSectionIdentifierEnumZero + 1]);
   EXPECT_NSEQ(@"entry", section_1[0].text);
   EXPECT_OCMOCK_VERIFY(mock_delegate);
@@ -227,8 +236,8 @@
   base::Time today =
       base::Time::Now().LocalMidnight() + base::TimeDelta::FromHours(1);
   base::TimeDelta day = base::TimeDelta::FromDays(1);
-  LegacyHistoryEntryItem* day1 = TestHistoryEntryItem(today, "day1");
-  LegacyHistoryEntryItem* day2 = TestHistoryEntryItem(today - day, "day2");
+  HistoryEntryItem* day1 = TestHistoryEntryItem(today, "day1");
+  HistoryEntryItem* day2 = TestHistoryEntryItem(today - day, "day2");
 
   OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_;
 
diff --git a/ios/chrome/browser/ui/history/history_panel_view_controller.h b/ios/chrome/browser/ui/history/history_panel_view_controller.h
deleted file mode 100644
index a2c4743..0000000
--- a/ios/chrome/browser/ui/history/history_panel_view_controller.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_PANEL_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_PANEL_VIEW_CONTROLLER_H_
-
-#import <UIKit/UIKit.h>
-
-namespace ios {
-class ChromeBrowserState;
-}
-
-@protocol ApplicationCommands;
-@protocol UrlLoader;
-
-// View controller for displaying the history panel.
-@interface HistoryPanelViewController : UIViewController
-
-- (instancetype)initWithLoader:(id<UrlLoader>)loader
-                  browserState:(ios::ChromeBrowserState*)browserState
-                    dispatcher:(id<ApplicationCommands>)dispatcher
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithNibName:(NSString*)nibNameOrNil
-                         bundle:(NSBundle*)nibBundleOrNil NS_UNAVAILABLE;
-- (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
-
-@end
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_PANEL_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/history/history_panel_view_controller.mm b/ios/chrome/browser/ui/history/history_panel_view_controller.mm
deleted file mode 100644
index 8730241..0000000
--- a/ios/chrome/browser/ui/history/history_panel_view_controller.mm
+++ /dev/null
@@ -1,407 +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.
-
-#import "ios/chrome/browser/ui/history/history_panel_view_controller.h"
-
-#include <memory>
-
-#include "base/ios/block_types.h"
-#include "base/metrics/user_metrics.h"
-#include "base/metrics/user_metrics_action.h"
-#include "components/browser_sync/profile_sync_service.h"
-#include "components/history/core/browser/browsing_history_service.h"
-#include "components/keyed_service/core/service_access_type.h"
-#include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/history/history_service_factory.h"
-#include "ios/chrome/browser/sync/profile_sync_service_factory.h"
-#import "ios/chrome/browser/ui/commands/application_commands.h"
-#import "ios/chrome/browser/ui/history/clear_browsing_bar.h"
-#import "ios/chrome/browser/ui/history/history_search_view_controller.h"
-#include "ios/chrome/browser/ui/history/ios_browsing_history_driver.h"
-#import "ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h"
-#import "ios/chrome/browser/ui/icons/chrome_icon.h"
-#import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
-#import "ios/chrome/browser/ui/material_components/utils.h"
-#import "ios/chrome/browser/ui/ntp/recent_tabs/views/panel_bar_view.h"
-#import "ios/chrome/browser/ui/uikit_ui_util.h"
-#import "ios/chrome/browser/ui/url_loader.h"
-#import "ios/chrome/common/ui_util/constraints_ui_util.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/AppBar/src/MDCAppBarViewController.h"
-#import "ios/third_party/material_components_ios/src/components/NavigationBar/src/MaterialNavigationBar.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Shadow opacity for the clear browsing button and the header when scrolling.
-CGFloat kShadowOpacity = 0.2f;
-}  // namespace
-
-@interface HistoryPanelViewController ()<
-    LegacyHistoryCollectionViewControllerDelegate,
-    HistorySearchViewControllerDelegate> {
-  // Controller for collection view that displays history entries.
-  LegacyHistoryCollectionViewController* _historyCollectionController;
-  // Bar at the bottom of the history panel the displays options for entry
-  // deletion, including "Clear Browsing Data..." which takes the user to
-  // Privacy settings, or "Edit" for entering a mode for deleting individual
-  // entries. When in edit mode, the bar displays options to Delete or Cancel.
-  ClearBrowsingBar* _clearBrowsingBar;
-  // View controller for the search bar.
-  HistorySearchViewController* _searchViewController;
-  // Container view for history collection and clear browsing button to enable
-  // use of autolayout in conjunction with Material App Bar.
-  UIView* _containerView;
-  // The header view controller.
-  MDCAppBarViewController* _appBarViewController;
-  // Left bar button item for Search.
-  UIBarButtonItem* _leftBarButtonItem;
-  // Right bar button item for Dismiss history action.
-  UIBarButtonItem* _rightBarButtonItem;
-  // YES if NSLayoutConstraits were added.
-  BOOL _addedConstraints;
-  // Provides dependencies and funnels callbacks from BrowsingHistoryService.
-  std::unique_ptr<IOSBrowsingHistoryDriver> _browsingHistoryDriver;
-  // Abstraction to communicate with HistoryService and WebHistoryService.
-  std::unique_ptr<history::BrowsingHistoryService> _browsingHistoryService;
-}
-// Closes history.
-- (void)closeHistory;
-// Closes history, invoking completionHandler once dismissal is complete.
-- (void)closeHistoryWithCompletion:(ProceduralBlock)completionHandler;
-// Opens Privacy settings.
-- (void)openPrivacySettings;
-// Configure view for editing mode.
-- (void)enterEditingMode;
-// Configure view for non-editing mode.
-- (void)exitEditingMode;
-// Deletes selected history entries.
-- (void)deleteSelectedItems;
-// Displays a search bar for searching history entries.
-- (void)enterSearchMode;
-// Dismisses the search bar.
-- (void)exitSearchMode;
-// Configures navigation bar for current state of the history collection.
-- (void)configureNavigationBar;
-// Configures the clear browsing data bar for the current state of the history
-// collection.
-- (void)configureClearBrowsingBar;
-
-// The dispatcher used by this ViewController.
-@property(nonatomic, readonly, weak) id<ApplicationCommands> dispatcher;
-
-@end
-
-@implementation HistoryPanelViewController
-
-@synthesize dispatcher = _dispatcher;
-
-- (instancetype)initWithLoader:(id<UrlLoader>)loader
-                  browserState:(ios::ChromeBrowserState*)browserState
-                    dispatcher:(id<ApplicationCommands>)dispatcher {
-  self = [super initWithNibName:nil bundle:nil];
-  if (self) {
-    _historyCollectionController =
-        [[LegacyHistoryCollectionViewController alloc]
-            initWithLoader:loader
-              browserState:browserState
-                  delegate:self];
-
-    _browsingHistoryDriver = std::make_unique<IOSBrowsingHistoryDriver>(
-        browserState, _historyCollectionController);
-
-    _browsingHistoryService = std::make_unique<history::BrowsingHistoryService>(
-        _browsingHistoryDriver.get(),
-        ios::HistoryServiceFactory::GetForBrowserState(
-            browserState, ServiceAccessType::EXPLICIT_ACCESS),
-        ProfileSyncServiceFactory::GetForBrowserState(browserState));
-
-    _historyCollectionController.historyService = _browsingHistoryService.get();
-
-    _dispatcher = dispatcher;
-
-    // Configure modal presentation.
-    [self setModalPresentationStyle:UIModalPresentationFormSheet];
-    [self setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
-
-    // Add and configure header.
-    _appBarViewController = [[MDCAppBarViewController alloc] init];
-  }
-  return self;
-}
-
-- (instancetype)initWithNibName:(NSString*)nibNameOrNil
-                         bundle:(NSBundle*)nibBundleOrNil {
-  NOTREACHED();
-  return nil;
-}
-
-- (instancetype)initWithCoder:(NSCoder*)aDecoder {
-  NOTREACHED();
-  return nil;
-}
-
-- (void)viewDidLoad {
-  [super viewDidLoad];
-  [self setTitle:l10n_util::GetNSString(IDS_HISTORY_TITLE)];
-
-  _containerView = [[UIView alloc] initWithFrame:self.view.frame];
-  [_containerView setAutoresizingMask:UIViewAutoresizingFlexibleWidth |
-                                      UIViewAutoresizingFlexibleHeight];
-  [self.view addSubview:_containerView];
-
-  [[_historyCollectionController view]
-      setTranslatesAutoresizingMaskIntoConstraints:NO];
-  [_historyCollectionController willMoveToParentViewController:self];
-  [_containerView addSubview:[_historyCollectionController view]];
-  [self addChildViewController:_historyCollectionController];
-  [_historyCollectionController didMoveToParentViewController:self];
-
-  _clearBrowsingBar = [[ClearBrowsingBar alloc] initWithFrame:CGRectZero];
-  [_clearBrowsingBar setClearBrowsingDataTarget:self
-                                         action:@selector(openPrivacySettings)];
-  [_clearBrowsingBar setEditTarget:self action:@selector(enterEditingMode)];
-  [_clearBrowsingBar setCancelTarget:self action:@selector(exitEditingMode)];
-  [_clearBrowsingBar setDeleteTarget:self
-                              action:@selector(deleteSelectedItems)];
-  [_clearBrowsingBar setTranslatesAutoresizingMaskIntoConstraints:NO];
-  [_containerView addSubview:_clearBrowsingBar];
-  [self configureClearBrowsingBar];
-
-  ConfigureAppBarViewControllerWithCardStyle(_appBarViewController);
-  [self addChildViewController:_appBarViewController];
-  _appBarViewController.headerView.trackingScrollView =
-      [_historyCollectionController collectionView];
-  [self.view addSubview:_appBarViewController.view];
-  [_appBarViewController didMoveToParentViewController:self];
-  // Prevent the touch events on appBar from being forwarded to the
-  // collectionView.  See https://crbug.com/773580
-  [_appBarViewController.headerView
-      stopForwardingTouchEventsForView:_appBarViewController.navigationBar];
-
-  // Add navigation bar buttons.
-  _leftBarButtonItem =
-      [ChromeIcon templateBarButtonItemWithImage:[ChromeIcon searchIcon]
-                                          target:self
-                                          action:@selector(enterSearchMode)];
-  self.navigationItem.leftBarButtonItem = _leftBarButtonItem;
-  _rightBarButtonItem = [[UIBarButtonItem alloc]
-      initWithTitle:l10n_util::GetNSString(IDS_IOS_NAVIGATION_BAR_DONE_BUTTON)
-              style:UIBarButtonItemStylePlain
-             target:self
-             action:@selector(closeHistory)];
-  self.navigationItem.rightBarButtonItem = _rightBarButtonItem;
-  [self configureNavigationBar];
-}
-
-- (void)updateViewConstraints {
-  if (!_addedConstraints) {
-    NSDictionary* views = @{
-      @"collectionView" : [_historyCollectionController view],
-      @"clearBrowsingBar" : _clearBrowsingBar,
-    };
-    NSArray* constraints = @[
-      @"V:|[collectionView][clearBrowsingBar]|", @"H:|[collectionView]|",
-      @"H:|[clearBrowsingBar]|"
-    ];
-    ApplyVisualConstraints(constraints, views);
-    _addedConstraints = YES;
-  }
-  [super updateViewConstraints];
-}
-
-- (BOOL)disablesAutomaticKeyboardDismissal {
-  return NO;
-}
-
-- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)orient {
-  [super didRotateFromInterfaceOrientation:orient];
-  [_clearBrowsingBar updateHeight];
-}
-
-#pragma mark - HistoryCollectionViewControllerDelegate
-
-- (void)historyCollectionViewController:
-            (LegacyHistoryCollectionViewController*)collectionViewcontroller
-              shouldCloseWithCompletion:(ProceduralBlock)completionHandler {
-  [self closeHistoryWithCompletion:completionHandler];
-}
-
-- (void)historyCollectionViewController:
-            (LegacyHistoryCollectionViewController*)controller
-                      didScrollToOffset:(CGPoint)offset {
-  // Display a shadow on the header when the collection is scrolled.
-  MDCFlexibleHeaderView* headerView = _appBarViewController.headerView;
-  headerView.visibleShadowOpacity =
-      offset.y > -CGRectGetHeight(headerView.frame) ? kShadowOpacity : 0.0f;
-}
-
-- (void)historyCollectionViewControllerDidChangeEntries:
-    (LegacyHistoryCollectionViewController*)controller {
-  // Reconfigure the navigation and clear browsing bars to reflect currently
-  // displayed entries.
-  [self configureNavigationBar];
-  [self configureClearBrowsingBar];
-}
-
-- (void)historyCollectionViewControllerDidChangeEntrySelection:
-    (LegacyHistoryCollectionViewController*)controller {
-  // Reconfigure the clear browsing bar to reflect current availability of
-  // entries for deletion.
-  [self configureClearBrowsingBar];
-}
-
-#pragma mark - HistorySearchViewControllerDelegate
-
-- (void)historySearchViewController:
-            (HistorySearchViewController*)searchViewController
-            didRequestSearchForTerm:(NSString*)searchTerm {
-  [_historyCollectionController showHistoryMatchingQuery:searchTerm];
-}
-
-- (void)historySearchViewControllerDidCancel:
-    (HistorySearchViewController*)searchViewController {
-  DCHECK([_searchViewController isEqual:searchViewController]);
-  [self exitSearchMode];
-}
-
-#pragma mark UIAccessibilityAction
-
-- (BOOL)accessibilityPerformEscape {
-  [self closeHistory];
-  return YES;
-}
-
-#pragma mark - Private methods
-
-- (void)closeHistory {
-  [self closeHistoryWithCompletion:nil];
-}
-
-- (void)closeHistoryWithCompletion:(ProceduralBlock)completion {
-  [self.presentingViewController dismissViewControllerAnimated:YES
-                                                    completion:completion];
-}
-
-- (void)openPrivacySettings {
-  // Ignore the button tap if view controller presenting.
-  if ([self presentedViewController]) {
-    return;
-  }
-  [self exitSearchMode];
-  base::RecordAction(
-      base::UserMetricsAction("HistoryPage_InitClearBrowsingData"));
-  [self.dispatcher showClearBrowsingDataSettingsFromViewController:self];
-}
-
-- (void)enterEditingMode {
-  // Ignore the button tap if view controller presenting.
-  if ([self presentedViewController]) {
-    return;
-  }
-  [_historyCollectionController setEditing:YES];
-  [_clearBrowsingBar setEditing:YES];
-  if (_historyCollectionController.searching) {
-    [_searchViewController setEnabled:NO];
-  }
-  DCHECK([_historyCollectionController isEditing]);
-  [self configureNavigationBar];
-}
-
-- (void)exitEditingMode {
-  [_historyCollectionController setEditing:NO];
-  [_clearBrowsingBar setEditing:NO];
-  if (_historyCollectionController.searching) {
-    [_searchViewController setEnabled:YES];
-  }
-  DCHECK(![_historyCollectionController isEditing]);
-  [self configureNavigationBar];
-}
-
-- (void)deleteSelectedItems {
-  [_historyCollectionController deleteSelectedItemsFromHistory];
-  base::RecordAction(base::UserMetricsAction("HistoryPage_RemoveSelected"));
-  [self exitEditingMode];
-}
-- (void)enterSearchMode {
-  if (!_searchViewController) {
-    _searchViewController = [[HistorySearchViewController alloc] init];
-    [_searchViewController setDelegate:self];
-  }
-
-  UIView* searchBarView = [_searchViewController view];
-  [_searchViewController willMoveToParentViewController:self];
-  [self.view addSubview:searchBarView];
-  _historyCollectionController.searching = YES;
-  [_searchViewController didMoveToParentViewController:self];
-  base::RecordAction(base::UserMetricsAction("HistoryPage_Search"));
-
-  // Constraints to make search bar cover header.
-  [searchBarView setTranslatesAutoresizingMaskIntoConstraints:NO];
-  MDCFlexibleHeaderView* headerView = _appBarViewController.headerView;
-  NSArray* constraints = @[
-    [[searchBarView topAnchor] constraintEqualToAnchor:headerView.topAnchor],
-    [[searchBarView leadingAnchor]
-        constraintEqualToAnchor:headerView.leadingAnchor],
-    [[searchBarView heightAnchor]
-        constraintEqualToAnchor:headerView.heightAnchor],
-    [[searchBarView widthAnchor] constraintEqualToAnchor:headerView.widthAnchor]
-  ];
-  [NSLayoutConstraint activateConstraints:constraints];
-  // Workaround so navigationItems are not voice-over selectable while hidden by
-  // the search view. We might have to re factor the view hierarchy in order to
-  // properly solve this issue. See: https://codereview.chromium.org/2605023002/
-  self.navigationItem.leftBarButtonItem = nil;
-  self.navigationItem.rightBarButtonItem = nil;
-}
-
-- (void)exitSearchMode {
-  if (_historyCollectionController.searching) {
-    // Resets the navigation items to their initial state.
-    self.navigationItem.leftBarButtonItem = _leftBarButtonItem;
-    self.navigationItem.rightBarButtonItem = _rightBarButtonItem;
-    [self configureNavigationBar];
-
-    [[_searchViewController view] removeFromSuperview];
-    [_searchViewController removeFromParentViewController];
-    _historyCollectionController.searching = NO;
-    [_historyCollectionController showHistoryMatchingQuery:nil];
-  }
-}
-
-- (void)configureNavigationBar {
-  // The search button should only be enabled if there are history entries to
-  // search, and if history is not in edit mode.
-  self.navigationItem.leftBarButtonItem.enabled =
-      ![_historyCollectionController isEmpty] &&
-      ![_historyCollectionController isEditing];
-}
-
-- (void)configureClearBrowsingBar {
-  _clearBrowsingBar.editing = _historyCollectionController.editing;
-  _clearBrowsingBar.deleteButtonEnabled =
-      [_historyCollectionController hasSelectedEntries];
-  _clearBrowsingBar.editButtonEnabled = ![_historyCollectionController isEmpty];
-}
-
-#pragma mark - UIResponder
-
-- (BOOL)canBecomeFirstResponder {
-  return YES;
-}
-
-- (NSArray*)keyCommands {
-  __weak HistoryPanelViewController* weakSelf = self;
-  return @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape
-                                   modifierFlags:Cr_UIKeyModifierNone
-                                           title:nil
-                                          action:^{
-                                            [weakSelf closeHistory];
-                                          }] ];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/history/history_search_view.h b/ios/chrome/browser/ui/history/history_search_view.h
deleted file mode 100644
index 6628cda..0000000
--- a/ios/chrome/browser/ui/history/history_search_view.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_H_
-
-#import <UIKit/UIKit.h>
-
-// View for displaying a search bar in history.
-@interface HistorySearchView : UIView
-
-// YES if the search view is in an enabled state. When not enabled, the search
-// view text is greyed out, the clear button is removed, and the cancel button
-// is disabled.
-@property(nonatomic, getter=isEnabled) BOOL enabled;
-
-// Sets the target/action of the cancel button.
-- (void)setCancelTarget:(id)target action:(SEL)action;
-
-// Sets the delegate of the search bar.
-- (void)setSearchBarDelegate:(id<UITextFieldDelegate>)delegate;
-
-// Clears the search bar text.
-- (void)clearText;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_H_
diff --git a/ios/chrome/browser/ui/history/history_search_view.mm b/ios/chrome/browser/ui/history/history_search_view.mm
deleted file mode 100644
index 1e06e2754..0000000
--- a/ios/chrome/browser/ui/history/history_search_view.mm
+++ /dev/null
@@ -1,134 +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.
-
-#import "ios/chrome/browser/ui/history/history_search_view.h"
-
-#include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/ui/uikit_ui_util.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Shadow opacity for the search view.
-CGFloat kShadowOpacity = 0.2f;
-// Margin for the search view.
-CGFloat kHorizontalMargin = 16.0f;
-}  // namespace
-
-@interface HistorySearchView ()
-
-// Stack view for laying out the text field and cancel button.
-@property(nonatomic, strong) UIStackView* stackView;
-// Text field for the search view.
-@property(nonatomic, strong) UITextField* textField;
-// Cancel button for dismissing the search view.
-@property(nonatomic, strong) UIButton* cancelButton;
-// Constraint for the top anchor.
-@property(nonatomic, strong) NSLayoutConstraint* topAnchorConstraint;
-
-@end
-
-@implementation HistorySearchView
-
-@synthesize enabled = _enabled;
-@synthesize stackView = _stackView;
-@synthesize textField = _textField;
-@synthesize cancelButton = _cancelButton;
-@synthesize topAnchorConstraint = _topAnchorConstraint;
-
-- (instancetype)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    [self setBackgroundColor:[UIColor whiteColor]];
-    [[self layer] setShadowOpacity:kShadowOpacity];
-
-    _textField = [[UITextField alloc] init];
-    _textField.contentVerticalAlignment =
-        UIControlContentVerticalAlignmentCenter;
-    _textField.backgroundColor = [UIColor whiteColor];
-    _textField.textColor =
-        [UIColor colorWithWhite:0 alpha:[MDCTypography body1FontOpacity]];
-    _textField.font = [MDCTypography subheadFont];
-    _textField.borderStyle = UITextBorderStyleNone;
-    [_textField setLeftViewMode:UITextFieldViewModeNever];
-    _textField.clearButtonMode = UITextFieldViewModeAlways;
-    _textField.placeholder = l10n_util::GetNSString(IDS_HISTORY_SEARCH_BUTTON);
-
-    _cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    [_cancelButton setImage:[UIImage imageNamed:@"collapse"]
-                   forState:UIControlStateNormal];
-    [_cancelButton setImage:[UIImage imageNamed:@"collapse_pressed"]
-                   forState:UIControlStateHighlighted];
-    [_cancelButton
-        setContentCompressionResistancePriority:UILayoutPriorityRequired
-                                        forAxis:
-                                            UILayoutConstraintAxisHorizontal];
-    [_cancelButton setContentHuggingPriority:UILayoutPriorityRequired
-                                     forAxis:UILayoutConstraintAxisHorizontal];
-    [_cancelButton setAccessibilityLabel:l10n_util::GetNSString(IDS_CANCEL)];
-
-    _stackView = [[UIStackView alloc]
-        initWithArrangedSubviews:@[ _textField, _cancelButton ]];
-    _stackView.alignment = UIStackViewAlignmentFill;
-    _stackView.axis = UILayoutConstraintAxisHorizontal;
-    _stackView.distribution = UIStackViewDistributionFill;
-    [self addSubview:_stackView];
-    _stackView.translatesAutoresizingMaskIntoConstraints = NO;
-    _stackView.layoutMarginsRelativeArrangement = YES;
-
-    CGFloat topAnchorConstant = IsCompactWidth() ? StatusBarHeight() : 0;
-    _topAnchorConstraint =
-        [_stackView.topAnchor constraintEqualToAnchor:self.topAnchor
-                                             constant:topAnchorConstant];
-    [NSLayoutConstraint activateConstraints:@[
-      _topAnchorConstraint,
-      [_stackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
-      [_stackView.layoutMarginsGuide.leadingAnchor
-          constraintEqualToAnchor:self.leadingAnchor
-                         constant:kHorizontalMargin],
-      [_stackView.layoutMarginsGuide.trailingAnchor
-          constraintEqualToAnchor:self.trailingAnchor
-                         constant:-kHorizontalMargin],
-    ]];
-  }
-  return self;
-}
-
-- (BOOL)becomeFirstResponder {
-  return [self.textField becomeFirstResponder];
-}
-
-- (void)setEnabled:(BOOL)enabled {
-  _enabled = enabled;
-  self.cancelButton.enabled = enabled;
-  self.textField.enabled = enabled;
-  self.textField.clearButtonMode =
-      enabled ? UITextFieldViewModeAlways : UITextFieldViewModeNever;
-}
-
-- (void)setCancelTarget:(id)target action:(SEL)action {
-  [_cancelButton addTarget:target
-                    action:action
-          forControlEvents:UIControlEventTouchUpInside];
-}
-
-- (void)setSearchBarDelegate:(id<UITextFieldDelegate>)delegate {
-  [self.textField setDelegate:delegate];
-}
-
-- (void)clearText {
-  self.textField.text = nil;
-}
-
-#pragma mark - UITraitEnvironment
-
-- (void)traitCollectionDidChange:(UITraitCollection*)previousTraitCollection {
-  self.topAnchorConstraint.constant = IsCompactWidth() ? StatusBarHeight() : 0;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/history/history_search_view_controller.h b/ios/chrome/browser/ui/history/history_search_view_controller.h
deleted file mode 100644
index 5305fd74..0000000
--- a/ios/chrome/browser/ui/history/history_search_view_controller.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_CONTROLLER_H_
-
-#import <UIKit/UIKit.h>
-
-@class HistorySearchViewController;
-
-// Delegate for HistorySearchViewController. Used to pass on search bar
-// interactions.
-@protocol HistorySearchViewControllerDelegate<NSObject>
-// Called when the search button is clicked.
-- (void)historySearchViewController:
-            (HistorySearchViewController*)historySearchViewController
-            didRequestSearchForTerm:(NSString*)searchTerm;
-// Called when the search view's cancel button is clicked.
-- (void)historySearchViewControllerDidCancel:
-    (HistorySearchViewController*)historySearchViewController;
-@end
-
-// Controller for the search bar used in the history panel.
-@interface HistorySearchViewController : UIViewController
-
-// Delegate for forwarding interactions with the search view.
-@property(nonatomic, weak) id<HistorySearchViewControllerDelegate> delegate;
-// YES if the search view is enabled. Setting this property enables or disables
-// the search view, as appropriate.
-@property(nonatomic, getter=isEnabled) BOOL enabled;
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_HISTORY_SEARCH_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/history/history_search_view_controller.mm b/ios/chrome/browser/ui/history/history_search_view_controller.mm
deleted file mode 100644
index 653e5b7..0000000
--- a/ios/chrome/browser/ui/history/history_search_view_controller.mm
+++ /dev/null
@@ -1,71 +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.
-
-#import "ios/chrome/browser/ui/history/history_search_view_controller.h"
-
-#import "ios/chrome/browser/ui/history/history_search_view.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface HistorySearchViewController ()<UITextFieldDelegate> {
-  // View displayed by the HistorySearchViewController
-  HistorySearchView* _searchView;
-}
-
-// Action for the cancel button.
-- (void)cancelButtonClicked:(id)sender;
-
-@end
-
-@implementation HistorySearchViewController
-@synthesize delegate = _delegate;
-@synthesize enabled = _enabled;
-
-- (void)loadView {
-  _searchView = [[HistorySearchView alloc] init];
-  [_searchView setSearchBarDelegate:self];
-  [_searchView setCancelTarget:self action:@selector(cancelButtonClicked:)];
-  self.view = _searchView;
-}
-
-- (void)viewDidAppear:(BOOL)animated {
-  [super viewDidAppear:animated];
-  [_searchView becomeFirstResponder];
-}
-
-- (void)setEnabled:(BOOL)enabled {
-  _enabled = enabled;
-  [_searchView setEnabled:enabled];
-}
-
-- (void)cancelButtonClicked:(id)sender {
-  [_searchView clearText];
-  [_searchView endEditing:YES];
-  [self.delegate historySearchViewControllerDidCancel:self];
-}
-
-#pragma mark - UITextFieldDelegate
-
-- (BOOL)textField:(UITextField*)textField
-    shouldChangeCharactersInRange:(NSRange)range
-                replacementString:(NSString*)string {
-  NSMutableString* text = [NSMutableString stringWithString:[textField text]];
-  [text replaceCharactersInRange:range withString:string];
-  [self.delegate historySearchViewController:self didRequestSearchForTerm:text];
-  return YES;
-}
-
-- (BOOL)textFieldShouldClear:(UITextField*)textField {
-  [self.delegate historySearchViewController:self didRequestSearchForTerm:@""];
-  return YES;
-}
-
-- (BOOL)textFieldShouldReturn:(UITextField*)textField {
-  [textField resignFirstResponder];
-  return YES;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/history/history_search_view_controller_unittest.mm b/ios/chrome/browser/ui/history/history_search_view_controller_unittest.mm
deleted file mode 100644
index 35ecd7a7..0000000
--- a/ios/chrome/browser/ui/history/history_search_view_controller_unittest.mm
+++ /dev/null
@@ -1,82 +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.
-
-#import "ios/chrome/browser/ui/history/history_search_view_controller.h"
-
-#include "base/mac/foundation_util.h"
-#import "ios/chrome/browser/ui/history/history_search_view.h"
-#include "testing/platform_test.h"
-#import "third_party/ocmock/OCMock/OCMock.h"
-#import "third_party/ocmock/gtest_support.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-// HistorySearchView category to expose the text field and cancel button.
-@interface HistorySearchView (Testing)
-@property(nonatomic, strong) UITextField* textField;
-@property(nonatomic, strong) UIButton* cancelButton;
-@end
-
-// Test fixture for HistorySearchViewController.
-class HistorySearchViewControllerTest : public PlatformTest {
- public:
-  HistorySearchViewControllerTest() {
-    search_view_controller_ = [[HistorySearchViewController alloc] init];
-    [search_view_controller_ loadView];
-    mock_delegate_ = [OCMockObject
-        mockForProtocol:@protocol(HistorySearchViewControllerDelegate)];
-    [search_view_controller_ setDelegate:mock_delegate_];
-  }
-
- protected:
-  __strong HistorySearchViewController* search_view_controller_;
-  __strong id<HistorySearchViewControllerDelegate> mock_delegate_;
-};
-
-// Test that pressing the cancel button invokes delegate callback to cancel
-// search.
-TEST_F(HistorySearchViewControllerTest, DISABLED_CancelButtonPressed) {
-  UIButton* cancel_button =
-      base::mac::ObjCCastStrict<HistorySearchView>(search_view_controller_.view)
-          .cancelButton;
-  OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_;
-  [[mock_delegate expect]
-      historySearchViewControllerDidCancel:search_view_controller_];
-  [cancel_button sendActionsForControlEvents:UIControlEventTouchUpInside];
-  EXPECT_OCMOCK_VERIFY(mock_delegate_);
-}
-
-// Test that invocation of
-// textField:shouldChangeCharactersInRange:replacementString: on the text field
-// delegate results invokes delegate callback to request search.
-TEST_F(HistorySearchViewControllerTest, DISABLED_SearchButtonPressed) {
-  UITextField* text_field =
-      base::mac::ObjCCastStrict<HistorySearchView>(search_view_controller_.view)
-          .textField;
-  OCMockObject* mock_delegate = (OCMockObject*)mock_delegate_;
-  [[mock_delegate expect] historySearchViewController:search_view_controller_
-                              didRequestSearchForTerm:@"a"];
-  [text_field.delegate textField:text_field
-      shouldChangeCharactersInRange:NSMakeRange(0, 0)
-                  replacementString:@"a"];
-  EXPECT_OCMOCK_VERIFY(mock_delegate);
-}
-
-// Test that disabling HistorySearchViewController disables the search view text
-// field.
-TEST_F(HistorySearchViewControllerTest, DISABLED_DisableSearchBar) {
-  UITextField* text_field =
-      base::mac::ObjCCastStrict<HistorySearchView>(search_view_controller_.view)
-          .textField;
-  DCHECK(text_field);
-  EXPECT_TRUE(text_field.enabled);
-
-  search_view_controller_.enabled = NO;
-  EXPECT_FALSE(text_field.enabled);
-
-  search_view_controller_.enabled = YES;
-  EXPECT_TRUE(text_field.enabled);
-}
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm
index 80d2c76e..95cc0a2 100644
--- a/ios/chrome/browser/ui/history/history_ui_egtest.mm
+++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -18,7 +18,6 @@
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
 #import "ios/chrome/browser/ui/authentication/signin_promo_view.h"
 #import "ios/chrome/browser/ui/history/history_ui_constants.h"
-#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h"
 #import "ios/chrome/browser/ui/settings/settings_collection_view_controller.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_url_item.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_constants.h"
@@ -66,7 +65,6 @@
   NSString* url_spec_text = nil;
   NSString* title_text = base::SysUTF8ToNSString(title);
 
-  if (IsUIRefreshPhase1Enabled()) {
     url_spec_text = base::SysUTF8ToNSString(url.GetOrigin().spec());
 
     MatchesBlock matches = ^BOOL(TableViewURLCell* cell) {
@@ -85,26 +83,6 @@
         [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches
                                              descriptionBlock:describe],
         grey_sufficientlyVisible(), nil);
-  } else {
-    url_spec_text = base::SysUTF8ToNSString(url.spec());
-
-    MatchesBlock matches = ^BOOL(LegacyHistoryEntryCell* cell) {
-      return [cell.textLabel.text isEqual:title_text] &&
-             [cell.detailTextLabel.text isEqual:url_spec_text];
-    };
-
-    DescribeToBlock describe = ^(id<GREYDescription> description) {
-      [description appendText:@"view containing URL text: "];
-      [description appendText:url_spec_text];
-      [description appendText:@" title text: "];
-      [description appendText:title_text];
-    };
-    return grey_allOf(
-        grey_kindOfClass([LegacyHistoryEntryCell class]),
-        [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches
-                                             descriptionBlock:describe],
-        grey_sufficientlyVisible(), nil);
-  }
 }
 // Matcher for the history button in the tools menu.
 id<GREYMatcher> HistoryButton() {
@@ -120,11 +98,7 @@
 }
 // Matcher for the search button.
 id<GREYMatcher> SearchIconButton() {
-  if (IsUIRefreshPhase1Enabled()) {
     return grey_accessibilityID(kHistorySearchControllerSearchBarIdentifier);
-  } else {
-    return ButtonWithAccessibilityLabelId(IDS_IOS_ICON_SEARCH);
-  }
 }
 // Matcher for the cancel button.
 id<GREYMatcher> CancelButton() {
@@ -256,29 +230,21 @@
   [[EarlGrey selectElementWithMatcher:SearchIconButton()]
       performAction:grey_tap()];
 
-  if (IsUIRefreshPhase1Enabled()) {
     // Verify that scrim is visible.
     [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
                                             kHistorySearchScrimIdentifier)]
         assertWithMatcher:grey_notNil()];
-  }
 
   NSString* searchString =
       [NSString stringWithFormat:@"%s", _URL1.path().c_str()];
-  if (IsUIRefreshPhase1Enabled()) {
-    [[EarlGrey selectElementWithMatcher:SearchIconButton()]
-        performAction:grey_typeText(searchString)];
-  } else {
-    [[EarlGrey selectElementWithMatcher:grey_keyWindow()]
-        performAction:grey_typeText(searchString)];
-  }
 
-  if (IsUIRefreshPhase1Enabled()) {
-    // Verify that scrim is not visible.
-    [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
-                                            kHistorySearchScrimIdentifier)]
-        assertWithMatcher:grey_nil()];
-  }
+  [[EarlGrey selectElementWithMatcher:SearchIconButton()]
+      performAction:grey_typeText(searchString)];
+
+  // Verify that scrim is not visible.
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(
+                                          kHistorySearchScrimIdentifier)]
+      assertWithMatcher:grey_nil()];
 
   [[EarlGrey selectElementWithMatcher:HistoryEntry(_URL1, kTitle1)]
       assertWithMatcher:grey_notNil()];
@@ -414,14 +380,9 @@
   [self openHistoryPanel];
   chrome_test_util::VerifyAccessibilityForCurrentScreen();
   // Close history.
-  if (IsUIRefreshPhase1Enabled()) {
     id<GREYMatcher> exitMatcher =
         grey_accessibilityID(kHistoryNavigationControllerDoneButtonIdentifier);
     [[EarlGrey selectElementWithMatcher:exitMatcher] performAction:grey_tap()];
-  } else {
-    [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
-        performAction:grey_tap()];
-  }
 }
 
 #pragma mark Helper Methods
diff --git a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h b/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h
deleted file mode 100644
index a319554..0000000
--- a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_COLLECTION_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_COLLECTION_VIEW_CONTROLLER_H_
-
-#import "ios/chrome/browser/ui/collection_view/collection_view_controller.h"
-
-#include "base/ios/block_types.h"
-#include "ios/chrome/browser/ui/history/history_consumer.h"
-
-namespace ios {
-class ChromeBrowserState;
-}
-
-@class LegacyHistoryCollectionViewController;
-@protocol UrlLoader;
-
-// Delegate for the history collection view controller.
-@protocol LegacyHistoryCollectionViewControllerDelegate<NSObject>
-// Notifies the delegate that history should be dismissed.
-- (void)historyCollectionViewController:
-            (LegacyHistoryCollectionViewController*)controller
-              shouldCloseWithCompletion:(ProceduralBlock)completionHandler;
-// Notifies the delegate that the collection view has scrolled to |offset|.
-- (void)historyCollectionViewController:
-            (LegacyHistoryCollectionViewController*)controller
-                      didScrollToOffset:(CGPoint)offset;
-// Notifies the delegate that history entries have been loaded or changed.
-- (void)historyCollectionViewControllerDidChangeEntries:
-    (LegacyHistoryCollectionViewController*)controller;
-// Notifies the delegate that history entries have been selected or deselected.
-- (void)historyCollectionViewControllerDidChangeEntrySelection:
-    (LegacyHistoryCollectionViewController*)controller;
-@end
-
-// View controller for displaying a collection of history entries.
-@interface LegacyHistoryCollectionViewController
-    : CollectionViewController<HistoryConsumer>
-// YES if the collection view is in editing mode. Setting |editing| turns
-// editing mode on or off accordingly.
-@property(nonatomic, assign, getter=isEditing) BOOL editing;
-// YES if the the search bar is present.
-@property(nonatomic, assign, getter=isSearching) BOOL searching;
-// YES if collection is currently displaying no history entries.
-@property(nonatomic, assign, readonly, getter=isEmpty) BOOL empty;
-// YES if the collection view has selected entries while in editing mode.
-@property(nonatomic, assign, readonly) BOOL hasSelectedEntries;
-// Abstraction to communicate with HistoryService and WebHistoryService.
-// Not owned by LegacyHistoryCollectionViewController.
-@property(nonatomic, assign) history::BrowsingHistoryService* historyService;
-
-- (instancetype)
-initWithLoader:(id<UrlLoader>)loader
-  browserState:(ios::ChromeBrowserState*)browserState
-      delegate:(id<LegacyHistoryCollectionViewControllerDelegate>)delegate
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithLayout:(UICollectionViewLayout*)layout
-                         style:(CollectionViewControllerStyle)style
-    NS_UNAVAILABLE;
-
-// Search history for text |query| and display the results. |query| may be nil.
-// If query is empty, show all history.
-- (void)showHistoryMatchingQuery:(NSString*)query;
-
-// Deletes selected items from browser history and removes them from the
-// collection.
-- (void)deleteSelectedItemsFromHistory;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_COLLECTION_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm b/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm
deleted file mode 100644
index 3bcfddc5..0000000
--- a/ios/chrome/browser/ui/history/legacy_history_collection_view_controller.mm
+++ /dev/null
@@ -1,911 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/chrome/browser/ui/history/legacy_history_collection_view_controller.h"
-
-#import <MobileCoreServices/MobileCoreServices.h>
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/mac/foundation_util.h"
-#include "base/metrics/user_metrics.h"
-#include "base/metrics/user_metrics_action.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/browsing_data/core/history_notice_utils.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/url_formatter/url_formatter.h"
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/chrome_url_constants.h"
-#import "ios/chrome/browser/metrics/new_tab_page_uma.h"
-#import "ios/chrome/browser/signin/authentication_service.h"
-#include "ios/chrome/browser/signin/authentication_service_factory.h"
-#include "ios/chrome/browser/sync/sync_setup_service.h"
-#include "ios/chrome/browser/sync/sync_setup_service_factory.h"
-#import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
-#import "ios/chrome/browser/ui/collection_view/cells/activity_indicator_cell.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_text_item.h"
-#import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
-#import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
-#import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
-#import "ios/chrome/browser/ui/history/features.h"
-#import "ios/chrome/browser/ui/history/history_entries_status_item_delegate.h"
-#include "ios/chrome/browser/ui/history/history_entry_inserter.h"
-#import "ios/chrome/browser/ui/history/history_entry_item_delegate.h"
-#include "ios/chrome/browser/ui/history/history_util.h"
-#include "ios/chrome/browser/ui/history/legacy_history_entries_status_item.h"
-#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h"
-#import "ios/chrome/browser/ui/url_loader.h"
-#import "ios/chrome/browser/ui/util/pasteboard_util.h"
-#import "ios/chrome/browser/ui/util/top_view_controller.h"
-#include "ios/chrome/grit/ios_strings.h"
-#import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MDCActivityIndicator.h"
-#import "ios/third_party/material_components_ios/src/components/Collections/src/MaterialCollections.h"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/web/public/navigation_manager.h"
-#import "ios/web/public/referrer.h"
-#import "ios/web/public/web_state/context_menu_params.h"
-#import "net/base/mac/url_conversions.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-using history::BrowsingHistoryService;
-
-namespace {
-typedef NS_ENUM(NSInteger, ItemType) {
-  ItemTypeHistoryEntry = kItemTypeEnumZero,
-  ItemTypeEntriesStatus,
-  ItemTypeActivityIndicator,
-};
-// Section identifier for the header (sync information) section.
-const NSInteger kEntriesStatusSectionIdentifier = kSectionIdentifierEnumZero;
-// Maximum number of entries to retrieve in a single query to history service.
-const int kMaxFetchCount = 100;
-// Horizontal inset for item separators.
-const CGFloat kSeparatorInset = 10;
-}
-
-@interface LegacyHistoryCollectionViewController ()<
-    HistoryEntriesStatusItemDelegate,
-    HistoryEntryInserterDelegate,
-    HistoryEntryItemDelegate> {
-  // The main browser state. Not owned by HistoryCollectionViewController.
-  ios::ChromeBrowserState* _browserState;
-  // Backing ivar for delegate property.
-  __weak id<LegacyHistoryCollectionViewControllerDelegate> _delegate;
-  // Backing ivar for URLLoader property.
-  __weak id<UrlLoader> _URLLoader;
-  // Closure to request next page of history.
-  base::OnceClosure _query_history_continuation;
-}
-
-// Object to manage insertion of history entries into the collection view model.
-@property(nonatomic, strong) HistoryEntryInserter* entryInserter;
-// Delegate for the history collection view.
-@property(nonatomic, weak, readonly)
-    id<LegacyHistoryCollectionViewControllerDelegate>
-        delegate;
-// UrlLoader for navigating to history entries.
-@property(nonatomic, weak, readonly) id<UrlLoader> URLLoader;
-// The current query for visible history entries.
-@property(nonatomic, copy) NSString* currentQuery;
-// Coordinator for displaying context menus for history entries.
-@property(nonatomic, strong) ContextMenuCoordinator* contextMenuCoordinator;
-// YES if there are no results to show.
-@property(nonatomic, assign) BOOL empty;
-// YES if the history panel should show a notice about additional forms of
-// browsing history.
-@property(nonatomic, assign)
-    BOOL shouldShowNoticeAboutOtherFormsOfBrowsingHistory;
-// YES if there is an outstanding history query.
-@property(nonatomic, assign, getter=isLoading) BOOL loading;
-// YES if there are no more history entries to load.
-@property(nonatomic, assign, getter=hasFinishedLoading) BOOL finishedLoading;
-// YES if the collection should be filtered by the next received query result.
-@property(nonatomic, assign) BOOL filterQueryResult;
-
-// Fetches history for search text |query|. If |query| is nil or the empty
-// string, all history is fetched. If continuation is false, then the most
-// recent results are fetched, otherwise the results more recent than the
-// previous query will be returned.
-- (void)fetchHistoryForQuery:(NSString*)query continuation:(BOOL)continuation;
-// Updates various elements after history items have been deleted from the
-// CollectionView.
-- (void)updateCollectionViewAfterDeletingEntries;
-// Updates header section to provide relevant information about the currently
-// displayed history entries.
-- (void)updateEntriesStatusMessage;
-// Removes selected items from the visible collection, but does not delete them
-// from browser history.
-- (void)removeSelectedItemsFromCollection;
-// Selects all items in the collection that are not included in entries.
-- (void)filterForHistoryEntries:(NSArray*)entries;
-// Deletes all items in the collection which indexes are included in indexArray,
-// needs to be run inside a performBatchUpdates block.
-- (void)deleteItemsFromCollectionViewModelWithIndex:(NSArray*)indexArray;
-// Adds loading indicator to the top of the history collection, if one is not
-// already present.
-- (void)addLoadingIndicator;
-// Displays context menu on cell pressed with gestureRecognizer.
-- (void)displayContextMenuInvokedByGestureRecognizer:
-    (UILongPressGestureRecognizer*)gestureRecognizer;
-// Opens URL in the current tab and dismisses the history view.
-- (void)openURL:(const GURL&)URL;
-// Opens URL in a new non-incognito tab and dismisses the history view.
-- (void)openURLInNewTab:(const GURL&)URL;
-// Opens URL in a new incognito tab and dismisses the history view.
-- (void)openURLInNewIncognitoTab:(const GURL&)URL;
-@end
-
-@implementation LegacyHistoryCollectionViewController
-
-@synthesize searching = _searching;
-@synthesize entryInserter = _entryInserter;
-@synthesize currentQuery = _currentQuery;
-@synthesize contextMenuCoordinator = _contextMenuCoordinator;
-@synthesize empty = _empty;
-@synthesize shouldShowNoticeAboutOtherFormsOfBrowsingHistory =
-    _shouldShowNoticeAboutOtherFormsOfBrowsingHistory;
-@synthesize loading = _loading;
-@synthesize finishedLoading = _finishedLoading;
-@synthesize filterQueryResult = _filterQueryResult;
-@synthesize historyService = _historyService;
-
-- (instancetype)
-initWithLoader:(id<UrlLoader>)loader
-  browserState:(ios::ChromeBrowserState*)browserState
-      delegate:(id<LegacyHistoryCollectionViewControllerDelegate>)delegate {
-  UICollectionViewLayout* layout = [[MDCCollectionViewFlowLayout alloc] init];
-  self =
-      [super initWithLayout:layout style:CollectionViewControllerStyleDefault];
-  if (self) {
-    _browserState = browserState;
-    _delegate = delegate;
-    _URLLoader = loader;
-    // TODO(crbug.com/764578): -loadModel should not be called from
-    // initializer. A possible fix is to move this call to -viewDidLoad.
-    // Consider moving the other complex code out of the initializer as well.
-    [self loadModel];
-    // Add initial info section as header.
-    [self.collectionViewModel
-        addSectionWithIdentifier:kEntriesStatusSectionIdentifier];
-    _entryInserter =
-        [[HistoryEntryInserter alloc] initWithModel:self.collectionViewModel];
-    _entryInserter.delegate = self;
-    _empty = YES;
-  }
-  return self;
-}
-
-- (void)viewDidLoad {
-  [super viewDidLoad];
-  [self showHistoryMatchingQuery:nil];
-  self.styler.cellLayoutType = MDCCollectionViewCellLayoutTypeList;
-  self.styler.separatorInset =
-      UIEdgeInsetsMake(0, kSeparatorInset, 0, kSeparatorInset);
-  self.styler.allowsItemInlay = NO;
-
-  // Never adjust the content inset on iOS11 or it will create padding on top of
-  // the first cell.
-  if (@available(iOS 11, *)) {
-    [self.collectionView setContentInsetAdjustmentBehavior:
-                             UIScrollViewContentInsetAdjustmentNever];
-  }
-
-  self.clearsSelectionOnViewWillAppear = NO;
-  self.collectionView.keyboardDismissMode =
-      UIScrollViewKeyboardDismissModeOnDrag;
-
-  UILongPressGestureRecognizer* longPressRecognizer = [
-      [UILongPressGestureRecognizer alloc]
-      initWithTarget:self
-              action:@selector(displayContextMenuInvokedByGestureRecognizer:)];
-  [self.collectionView addGestureRecognizer:longPressRecognizer];
-}
-
-// Since contentInsetAdjustmentBehavior is
-// UIScrollViewContentInsetAdjustmentNever on iOS11, update the horizontal
-// insets manually to respect the safeArea.
-- (void)viewSafeAreaInsetsDidChange {
-  [super viewSafeAreaInsetsDidChange];
-  UIEdgeInsets collectionContentInsets = self.collectionView.contentInset;
-  collectionContentInsets.left = self.view.safeAreaInsets.left;
-  collectionContentInsets.right = self.view.safeAreaInsets.right;
-  self.collectionView.contentInset = collectionContentInsets;
-}
-
-- (BOOL)isEditing {
-  return self.editor.isEditing;
-}
-
-- (void)setEditing:(BOOL)editing {
-  [self.editor setEditing:editing animated:YES];
-}
-
-- (void)setSearching:(BOOL)searching {
-  _searching = searching;
-  [self updateEntriesStatusMessage];
-}
-
-- (BOOL)hasSelectedEntries {
-  return self.collectionView.indexPathsForSelectedItems.count;
-}
-
-- (void)showHistoryMatchingQuery:(NSString*)query {
-  self.finishedLoading = NO;
-  self.currentQuery = query;
-  [self fetchHistoryForQuery:query continuation:false];
-}
-
-- (void)deleteSelectedItemsFromHistory {
-  NSArray* deletedIndexPaths = self.collectionView.indexPathsForSelectedItems;
-  std::vector<BrowsingHistoryService::HistoryEntry> entries;
-  for (NSIndexPath* indexPath in deletedIndexPaths) {
-    LegacyHistoryEntryItem* object =
-        base::mac::ObjCCastStrict<LegacyHistoryEntryItem>(
-            [self.collectionViewModel itemAtIndexPath:indexPath]);
-    BrowsingHistoryService::HistoryEntry entry;
-    entry.url = object.URL;
-    entry.all_timestamps.insert(object.timestamp.ToInternalValue());
-    entries.push_back(entry);
-  }
-  self.historyService->RemoveVisits(entries);
-  [self removeSelectedItemsFromCollection];
-}
-
-- (id<LegacyHistoryCollectionViewControllerDelegate>)delegate {
-  return _delegate;
-}
-
-- (id<UrlLoader>)URLLoader {
-  return _URLLoader;
-}
-
-#pragma mark - MDCollectionViewController
-
-// TODO(crbug.com/653547): Remove this once the MDC adds an option for
-// preventing the infobar from showing.
-- (void)updateFooterInfoBarIfNecessary {
-  // No-op. This prevents the default infobar from showing.
-}
-
-#pragma mark - HistoryEntriesStatusItemDelegate
-
-- (void)historyEntriesStatusItem:(LegacyHistoryEntriesStatusItem*)item
-               didRequestOpenURL:(const GURL&)URL {
-  [self openURLInNewTab:URL];
-}
-
-#pragma mark - HistoryEntryInserterDelegate
-
-- (void)historyEntryInserter:(HistoryEntryInserter*)inserter
-    didInsertItemAtIndexPath:(NSIndexPath*)indexPath {
-  [self.collectionView insertItemsAtIndexPaths:@[ indexPath ]];
-}
-
-- (void)historyEntryInserter:(HistoryEntryInserter*)inserter
-     didInsertSectionAtIndex:(NSInteger)sectionIndex {
-  [self.collectionView
-      insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]];
-}
-
-- (void)historyEntryInserter:(HistoryEntryInserter*)inserter
-     didRemoveSectionAtIndex:(NSInteger)sectionIndex {
-  [self.collectionView
-      deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]];
-}
-
-#pragma mark - LegacyHistoryEntryItemDelegate
-
-- (void)historyEntryItemDidRequestOpen:(LegacyHistoryEntryItem*)item {
-  [self openURL:item.URL];
-}
-
-- (void)historyEntryItemDidRequestDelete:(LegacyHistoryEntryItem*)item {
-  NSInteger sectionIdentifier =
-      [self.entryInserter sectionIdentifierForTimestamp:item.timestamp];
-  if ([self.collectionViewModel
-          hasSectionForSectionIdentifier:sectionIdentifier] &&
-      [self.collectionViewModel hasItem:item
-                inSectionWithIdentifier:sectionIdentifier]) {
-    NSIndexPath* indexPath = [self.collectionViewModel indexPathForItem:item];
-    [self.collectionView
-        selectItemAtIndexPath:indexPath
-                     animated:NO
-               scrollPosition:UICollectionViewScrollPositionNone];
-    [self deleteSelectedItemsFromHistory];
-  }
-}
-
-- (void)historyEntryItemDidRequestCopy:(LegacyHistoryEntryItem*)item {
-  StoreURLInPasteboard(item.URL);
-}
-
-- (void)historyEntryItemDidRequestOpenInNewTab:(LegacyHistoryEntryItem*)item {
-  [self openURLInNewTab:item.URL];
-}
-
-- (void)historyEntryItemDidRequestOpenInNewIncognitoTab:
-    (LegacyHistoryEntryItem*)item {
-  [self openURLInNewIncognitoTab:item.URL];
-}
-
-- (void)historyEntryItemShouldUpdateView:(LegacyHistoryEntryItem*)item {
-  NSInteger sectionIdentifier =
-      [self.entryInserter sectionIdentifierForTimestamp:item.timestamp];
-  // If the item is still in the model, reconfigure it.
-  if ([self.collectionViewModel
-          hasSectionForSectionIdentifier:sectionIdentifier] &&
-      [self.collectionViewModel hasItem:item
-                inSectionWithIdentifier:sectionIdentifier]) {
-    [self reconfigureCellsForItems:@[ item ]];
-  }
-}
-
-#pragma mark - HistoryConsumer
-
-- (void)historyQueryWasCompletedWithResults:
-            (const std::vector<BrowsingHistoryService::HistoryEntry>&)results
-                           queryResultsInfo:
-                               (const BrowsingHistoryService::QueryResultsInfo&)
-                                   queryResultsInfo
-                        continuationClosure:
-                            (base::OnceClosure)continuationClosure {
-  self.loading = NO;
-  _query_history_continuation = std::move(continuationClosure);
-
-  // If history sync is enabled and there hasn't been a response from synced
-  // history, try fetching again.
-  SyncSetupService* syncSetupService =
-      SyncSetupServiceFactory::GetForBrowserState(_browserState);
-  if (syncSetupService->IsSyncEnabled() &&
-      syncSetupService->IsDataTypeActive(syncer::HISTORY_DELETE_DIRECTIVES) &&
-      queryResultsInfo.sync_timed_out) {
-    [self showHistoryMatchingQuery:_currentQuery];
-    return;
-  }
-
-  // If there are no results and no URLs have been loaded, report that no
-  // history entries were found.
-  if (results.empty() && self.isEmpty) {
-    [self updateEntriesStatusMessage];
-    [self.delegate historyCollectionViewControllerDidChangeEntries:self];
-    return;
-  }
-
-  self.finishedLoading = queryResultsInfo.reached_beginning;
-  self.empty = NO;
-
-  // Header section should be updated outside of batch updates, otherwise
-  // loading indicator removal will not be observed.
-  [self updateEntriesStatusMessage];
-
-  if (base::FeatureList::IsEnabled(kHistoryBatchUpdatesFilter)) {
-    NSMutableArray* resultsItems = [NSMutableArray array];
-    NSString* searchQuery =
-        [base::SysUTF16ToNSString(queryResultsInfo.search_text) copy];
-    [self.collectionView performBatchUpdates:^{
-      // There should always be at least a header section present.
-      DCHECK([[self collectionViewModel] numberOfSections]);
-      for (const BrowsingHistoryService::HistoryEntry& entry : results) {
-        LegacyHistoryEntryItem* item =
-            [[LegacyHistoryEntryItem alloc] initWithType:ItemTypeHistoryEntry
-                                            historyEntry:entry
-                                            browserState:_browserState
-                                                delegate:self];
-        [resultsItems addObject:item];
-      }
-      [self.delegate historyCollectionViewControllerDidChangeEntries:self];
-      if (([self isSearching] && [searchQuery length] > 0 &&
-           [self.currentQuery isEqualToString:searchQuery]) ||
-          self.filterQueryResult) {
-        // If in search mode, filter out entries that are not part of the
-        // search result.
-        [self filterForHistoryEntries:resultsItems];
-        NSArray* deletedIndexPaths =
-            self.collectionView.indexPathsForSelectedItems;
-        [self deleteItemsFromCollectionViewModelWithIndex:deletedIndexPaths];
-        self.filterQueryResult = NO;
-      }
-      // Wait to insert until after the deletions are done, this is needed
-      // because performBatchUpdates processes deletion indexes first, and then
-      // inserts.
-      for (LegacyHistoryEntryItem* item in resultsItems) {
-        [self.entryInserter insertHistoryEntryItem:item];
-      }
-    }
-        completion:^(BOOL) {
-          [self updateCollectionViewAfterDeletingEntries];
-        }];
-  } else {
-    NSMutableArray* filterResults = [NSMutableArray array];
-    NSString* searchQuery =
-        [base::SysUTF16ToNSString(queryResultsInfo.search_text) copy];
-    [self.collectionView performBatchUpdates:^{
-      // There should always be at least a header section present.
-      DCHECK([[self collectionViewModel] numberOfSections]);
-      for (const BrowsingHistoryService::HistoryEntry& entry : results) {
-        LegacyHistoryEntryItem* item =
-            [[LegacyHistoryEntryItem alloc] initWithType:ItemTypeHistoryEntry
-                                            historyEntry:entry
-                                            browserState:_browserState
-                                                delegate:self];
-        [self.entryInserter insertHistoryEntryItem:item];
-        if ([self isSearching] || self.filterQueryResult) {
-          [filterResults addObject:item];
-        }
-      }
-      [self.delegate historyCollectionViewControllerDidChangeEntries:self];
-    }
-        completion:^(BOOL) {
-          if (([self isSearching] && [searchQuery length] > 0 &&
-               [self.currentQuery isEqualToString:searchQuery]) ||
-              self.filterQueryResult) {
-            // If in search mode, filter out entries that are not part of the
-            // search result.
-            [self filterForHistoryEntries:filterResults];
-            self.filterQueryResult = NO;
-          }
-        }];
-  }
-}
-
-- (void)showNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)shouldShowNotice {
-  self.shouldShowNoticeAboutOtherFormsOfBrowsingHistory = shouldShowNotice;
-  // Update the history entries status message if there is no query in progress.
-  if (!self.isLoading) {
-    [self updateEntriesStatusMessage];
-  }
-}
-
-- (void)historyWasDeleted {
-  // If history has been deleted, reload history filtering for the current
-  // results. This only observes local changes to history, i.e. removing
-  // history via the clear browsing data page.
-  self.filterQueryResult = YES;
-  [self showHistoryMatchingQuery:nil];
-}
-
-#pragma mark - MDCCollectionViewEditingDelegate
-
-- (BOOL)collectionViewAllowsEditing:(UICollectionView*)collectionView {
-  return YES;
-}
-
-- (BOOL)collectionView:(UICollectionView*)collectionView
-    canEditItemAtIndexPath:(NSIndexPath*)indexPath {
-  // All items except those in the header section may be edited.
-  return indexPath.section;
-}
-
-- (BOOL)collectionView:(UICollectionView*)collectionView
-    canSelectItemDuringEditingAtIndexPath:(NSIndexPath*)indexPath {
-  // All items except those in the header section may be edited.
-  return indexPath.section;
-}
-
-#pragma mark - MDCCollectionViewStylingDelegate
-
-- (BOOL)collectionView:(UICollectionView*)collectionView
-    shouldHideItemBackgroundAtIndexPath:(NSIndexPath*)indexPath {
-  // Display the entries status section (always the first section) without any
-  // background image or shadowing.
-  return !indexPath.section;
-}
-
-- (BOOL)collectionView:(UICollectionView*)collectionView
-    hidesInkViewAtIndexPath:(NSIndexPath*)indexPath {
-  return [indexPath isEqual:[NSIndexPath indexPathForItem:0 inSection:0]];
-}
-
-- (CGFloat)collectionView:(UICollectionView*)collectionView
-    cellHeightAtIndexPath:(NSIndexPath*)indexPath {
-  if (indexPath.section) {
-    return MDCCellDefaultTwoLineHeight;
-  } else {
-    DCHECK([indexPath isEqual:[NSIndexPath indexPathForItem:0 inSection:0]]);
-    // Configure size for loading indicator and entries status cells.
-    CollectionViewItem* item =
-        [self.collectionViewModel itemAtIndexPath:indexPath];
-    if ([item isKindOfClass:[CollectionViewTextItem class]]) {
-      return MDCCellDefaultOneLineHeight;
-    }
-    CGFloat height = [[item cellClass]
-        cr_preferredHeightForWidth:CGRectGetWidth(collectionView.bounds)
-                           forItem:item];
-    return height;
-  }
-}
-
-- (MDCCollectionViewCellStyle)collectionView:(UICollectionView*)collectionView
-                         cellStyleForSection:(NSInteger)section {
-  return section ? MDCCollectionViewCellStyleCard
-                 : MDCCollectionViewCellStyleDefault;
-}
-
-#pragma mark - UICollectionViewDelegate
-
-- (BOOL)collectionView:(UICollectionView*)collectionView
-    shouldSelectItemAtIndexPath:(NSIndexPath*)indexPath {
-  // The first section is not selectable.
-  return indexPath.section && [super collectionView:collectionView
-                                  shouldSelectItemAtIndexPath:indexPath];
-}
-
-- (void)collectionView:(UICollectionView*)collectionView
-    didSelectItemAtIndexPath:(NSIndexPath*)indexPath {
-  [super collectionView:collectionView didSelectItemAtIndexPath:indexPath];
-
-  if (self.isEditing) {
-    [self.delegate historyCollectionViewControllerDidChangeEntrySelection:self];
-  } else {
-    LegacyHistoryEntryItem* item =
-        base::mac::ObjCCastStrict<LegacyHistoryEntryItem>(
-            [self.collectionViewModel itemAtIndexPath:indexPath]);
-    [self openURL:item.URL];
-    if (self.isSearching) {
-      base::RecordAction(
-          base::UserMetricsAction("HistoryPage_SearchResultClick"));
-    } else {
-      base::RecordAction(base::UserMetricsAction("HistoryPage_EntryLinkClick"));
-    }
-  }
-}
-
-- (void)collectionView:(UICollectionView*)collectionView
-    didDeselectItemAtIndexPath:(NSIndexPath*)indexPath {
-  [super collectionView:collectionView didDeselectItemAtIndexPath:indexPath];
-  [self.delegate historyCollectionViewControllerDidChangeEntrySelection:self];
-}
-
-- (void)collectionView:(UICollectionView*)collectionView
-    didEndDisplayingCell:(UICollectionViewCell*)cell
-      forItemAtIndexPath:(NSIndexPath*)indexPath {
-  if ([cell isKindOfClass:[ActivityIndicatorCell class]]) {
-    [[base::mac::ObjCCast<ActivityIndicatorCell>(cell) activityIndicator]
-        stopAnimating];
-  }
-}
-#pragma mark - UIScrollViewDelegate
-
-- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
-  [super scrollViewDidScroll:scrollView];
-  // Adjust header shadow.
-  [self.delegate historyCollectionViewController:self
-                               didScrollToOffset:scrollView.contentOffset];
-
-  if (self.hasFinishedLoading)
-    return;
-
-  CGFloat insetHeight =
-      scrollView.contentInset.top + scrollView.contentInset.bottom;
-  CGFloat contentViewHeight = scrollView.bounds.size.height - insetHeight;
-  CGFloat contentHeight = scrollView.contentSize.height;
-  CGFloat contentOffset = scrollView.contentOffset.y;
-  CGFloat buffer = contentViewHeight;
-  // If the scroll view is approaching the end of loaded history, try to fetch
-  // more history. Do so when the content offset is greater than the content
-  // height minus the view height, minus a buffer to start the fetch early.
-  if (contentOffset > (contentHeight - contentViewHeight) - buffer &&
-      !self.isLoading) {
-    // If at end, try to grab more history.
-    NSInteger lastSection = [self.collectionViewModel numberOfSections] - 1;
-    NSInteger lastItemIndex =
-        [self.collectionViewModel numberOfItemsInSection:lastSection] - 1;
-    if (lastSection == 0 || lastItemIndex < 0) {
-      return;
-    }
-
-    [self fetchHistoryForQuery:_currentQuery continuation:true];
-  }
-}
-
-#pragma mark - Private methods
-
-- (void)fetchHistoryForQuery:(NSString*)query continuation:(BOOL)continuation {
-  self.loading = YES;
-  // Add loading indicator if no items are shown.
-  if (self.isEmpty && !self.isSearching) {
-    [self addLoadingIndicator];
-  }
-
-  if (continuation) {
-    DCHECK(_query_history_continuation);
-    std::move(_query_history_continuation).Run();
-  } else {
-    _query_history_continuation.Reset();
-
-    BOOL fetchAllHistory = !query || [query isEqualToString:@""];
-    base::string16 queryString =
-        fetchAllHistory ? base::string16() : base::SysNSStringToUTF16(query);
-    history::QueryOptions options;
-    options.duplicate_policy =
-        fetchAllHistory ? history::QueryOptions::REMOVE_DUPLICATES_PER_DAY
-                        : history::QueryOptions::REMOVE_ALL_DUPLICATES;
-    options.max_count = kMaxFetchCount;
-    options.matching_algorithm =
-        query_parser::MatchingAlgorithm::ALWAYS_PREFIX_SEARCH;
-    self.historyService->QueryHistory(queryString, options);
-  }
-}
-
-- (void)updateCollectionViewAfterDeletingEntries {
-  // If only the header section remains, there are no history entries.
-  if ([self.collectionViewModel numberOfSections] == 1) {
-    self.empty = YES;
-  }
-  [self updateEntriesStatusMessage];
-  [self.delegate historyCollectionViewControllerDidChangeEntries:self];
-}
-
-- (void)updateEntriesStatusMessage {
-  CollectionViewItem* entriesStatusItem = nil;
-  if (self.isEmpty) {
-    CollectionViewTextItem* noResultsItem =
-        [[CollectionViewTextItem alloc] initWithType:ItemTypeEntriesStatus];
-    noResultsItem.text =
-        self.isSearching ? l10n_util::GetNSString(IDS_HISTORY_NO_SEARCH_RESULTS)
-                         : l10n_util::GetNSString(IDS_HISTORY_NO_RESULTS);
-    entriesStatusItem = noResultsItem;
-  } else if (self.shouldShowNoticeAboutOtherFormsOfBrowsingHistory) {
-    LegacyHistoryEntriesStatusItem* historyEntriesStatusItem =
-        [[LegacyHistoryEntriesStatusItem alloc]
-            initWithType:ItemTypeEntriesStatus];
-    historyEntriesStatusItem.delegate = self;
-    historyEntriesStatusItem.hidden = self.isSearching;
-    entriesStatusItem = historyEntriesStatusItem;
-  }
-  // Replace the item in the first section if it exists. Then insert the new
-  // item if it exists.
-  NSArray* items = [self.collectionViewModel
-      itemsInSectionWithIdentifier:kEntriesStatusSectionIdentifier];
-  if ([items count]) {
-    // There should only ever be at most one item in this section.
-    DCHECK([items count] <= 1);
-    // Only update if the item has changed.
-    if ([items[0] isEqual:entriesStatusItem]) {
-      return;
-    }
-  }
-  [self.collectionView performBatchUpdates:^{
-    NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
-    if ([items count]) {
-      [self.collectionViewModel
-                 removeItemWithType:[self.collectionViewModel
-                                        itemTypeForIndexPath:indexPath]
-          fromSectionWithIdentifier:kEntriesStatusSectionIdentifier];
-      [self.collectionView deleteItemsAtIndexPaths:@[ indexPath ]];
-    }
-    if (entriesStatusItem) {
-      [self.collectionViewModel addItem:entriesStatusItem
-                toSectionWithIdentifier:kEntriesStatusSectionIdentifier];
-      [self.collectionView insertItemsAtIndexPaths:@[ indexPath ]];
-    }
-  }
-                                completion:nil];
-}
-
-- (void)removeSelectedItemsFromCollection {
-  NSArray* deletedIndexPaths = self.collectionView.indexPathsForSelectedItems;
-  if (base::FeatureList::IsEnabled(kHistoryBatchUpdatesFilter)) {
-    NSArray* deletedIndexPaths = self.collectionView.indexPathsForSelectedItems;
-    [self.collectionView performBatchUpdates:^{
-      [self deleteItemsFromCollectionViewModelWithIndex:deletedIndexPaths];
-    }
-        completion:^(BOOL) {
-          [self updateCollectionViewAfterDeletingEntries];
-        }];
-  } else {
-    [self.collectionView performBatchUpdates:^{
-      [self collectionView:self.collectionView
-          willDeleteItemsAtIndexPaths:deletedIndexPaths];
-      [self.collectionView deleteItemsAtIndexPaths:deletedIndexPaths];
-
-      // Remove any empty sections, except the header section.
-      for (int section = self.collectionView.numberOfSections - 1; section > 0;
-           --section) {
-        if (![self.collectionViewModel numberOfItemsInSection:section]) {
-          [self.entryInserter removeSection:section];
-        }
-      }
-    }
-        completion:^(BOOL) {
-          // If only the header section remains, there are no history entries.
-          if ([self.collectionViewModel numberOfSections] == 1) {
-            self.empty = YES;
-          }
-          [self updateEntriesStatusMessage];
-          [self.delegate historyCollectionViewControllerDidChangeEntries:self];
-        }];
-  }
-}
-
-- (void)deleteItemsFromCollectionViewModelWithIndex:(NSArray*)indexArray {
-  [self collectionView:self.collectionView
-      willDeleteItemsAtIndexPaths:indexArray];
-  [self.collectionView deleteItemsAtIndexPaths:indexArray];
-
-  // Remove any empty sections, except the header section.
-  for (int section = self.collectionView.numberOfSections - 1; section > 0;
-       --section) {
-    if (![self.collectionViewModel numberOfItemsInSection:section]) {
-      [self.entryInserter removeSection:section];
-    }
-  }
-}
-
-- (void)filterForHistoryEntries:(NSArray*)entries {
-  self.collectionView.allowsMultipleSelection = YES;
-  for (int section = 1; section < [self.collectionViewModel numberOfSections];
-       ++section) {
-    NSInteger sectionIdentifier =
-        [self.collectionViewModel sectionIdentifierForSection:section];
-    if ([self.collectionViewModel
-            hasSectionForSectionIdentifier:sectionIdentifier]) {
-      NSArray* items = [self.collectionViewModel
-          itemsInSectionWithIdentifier:sectionIdentifier];
-      for (id item in items) {
-        LegacyHistoryEntryItem* historyItem =
-            base::mac::ObjCCastStrict<LegacyHistoryEntryItem>(item);
-        if (![entries containsObject:historyItem]) {
-          NSIndexPath* indexPath =
-              [self.collectionViewModel indexPathForItem:historyItem];
-          [self.collectionView
-              selectItemAtIndexPath:indexPath
-                           animated:NO
-                     scrollPosition:UICollectionViewScrollPositionNone];
-        }
-      }
-    }
-  }
-  // If kHistoryBatchUpdatesFilter is not enabled the selected items will not be
-  // removed from the collection at this time.
-  if (!base::FeatureList::IsEnabled(kHistoryBatchUpdatesFilter))
-    [self removeSelectedItemsFromCollection];
-}
-
-- (void)addLoadingIndicator {
-  NSIndexPath* indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
-  if ([self.collectionViewModel hasItemAtIndexPath:indexPath] &&
-      [self.collectionViewModel itemTypeForIndexPath:indexPath] ==
-          ItemTypeActivityIndicator) {
-    // Do not add indicator a second time.
-    return;
-  }
-
-  [self.collectionView performBatchUpdates:^{
-    if ([self.collectionViewModel hasItemAtIndexPath:indexPath]) {
-      [self.collectionViewModel
-                 removeItemWithType:[self.collectionViewModel
-                                        itemTypeForIndexPath:indexPath]
-          fromSectionWithIdentifier:kSectionIdentifierEnumZero];
-      [self.collectionView deleteItemsAtIndexPaths:@[ indexPath ]];
-    }
-    CollectionViewItem* loadingIndicatorItem =
-        [[CollectionViewItem alloc] initWithType:ItemTypeActivityIndicator];
-    loadingIndicatorItem.cellClass = [ActivityIndicatorCell class];
-    [self.collectionViewModel addItem:loadingIndicatorItem
-              toSectionWithIdentifier:kEntriesStatusSectionIdentifier];
-    [self.collectionView insertItemsAtIndexPaths:@[ indexPath ]];
-  }
-                                completion:nil];
-}
-
-#pragma mark Context Menu
-
-- (void)displayContextMenuInvokedByGestureRecognizer:
-    (UILongPressGestureRecognizer*)gestureRecognizer {
-  if (gestureRecognizer.numberOfTouches != 1 || self.editing ||
-      gestureRecognizer.state != UIGestureRecognizerStateBegan) {
-    return;
-  }
-
-  CGPoint touchLocation =
-      [gestureRecognizer locationOfTouch:0 inView:self.collectionView];
-  NSIndexPath* touchedItemIndexPath =
-      [self.collectionView indexPathForItemAtPoint:touchLocation];
-  // If there's no index path, or the index path is for the header item, do not
-  // display a contextual menu.
-  if (!touchedItemIndexPath ||
-      [touchedItemIndexPath
-          isEqual:[NSIndexPath indexPathForItem:0 inSection:0]])
-    return;
-
-  LegacyHistoryEntryItem* entry =
-      base::mac::ObjCCastStrict<LegacyHistoryEntryItem>(
-          [self.collectionViewModel itemAtIndexPath:touchedItemIndexPath]);
-
-  __weak LegacyHistoryCollectionViewController* weakSelf = self;
-  web::ContextMenuParams params;
-  params.location = touchLocation;
-  params.view = self.collectionView;
-  NSString* menuTitle =
-      base::SysUTF16ToNSString(url_formatter::FormatUrl(entry.URL));
-  params.menu_title = [menuTitle copy];
-
-  // Present sheet/popover using controller that is added to view hierarchy.
-  // TODO(crbug.com/754642): Remove TopPresentedViewController().
-  UIViewController* topController =
-      top_view_controller::TopPresentedViewController();
-
-  self.contextMenuCoordinator =
-      [[ContextMenuCoordinator alloc] initWithBaseViewController:topController
-                                                          params:params];
-
-  // TODO(crbug.com/606503): Refactor context menu creation code to be shared
-  // with BrowserViewController.
-  // Add "Open in New Tab" option.
-  NSString* openInNewTabTitle =
-      l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB);
-  ProceduralBlock openInNewTabAction = ^{
-    [weakSelf openURLInNewTab:entry.URL];
-  };
-  [self.contextMenuCoordinator addItemWithTitle:openInNewTabTitle
-                                         action:openInNewTabAction];
-
-  // Add "Open in New Incognito Tab" option.
-  NSString* openInNewIncognitoTabTitle = l10n_util::GetNSStringWithFixup(
-      IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB);
-  ProceduralBlock openInNewIncognitoTabAction = ^{
-    [weakSelf openURLInNewIncognitoTab:entry.URL];
-  };
-  [self.contextMenuCoordinator addItemWithTitle:openInNewIncognitoTabTitle
-                                         action:openInNewIncognitoTabAction];
-
-  // Add "Copy URL" option.
-  NSString* copyURLTitle =
-      l10n_util::GetNSStringWithFixup(IDS_IOS_CONTENT_CONTEXT_COPY);
-  ProceduralBlock copyURLAction = ^{
-    StoreURLInPasteboard(entry.URL);
-  };
-  [self.contextMenuCoordinator addItemWithTitle:copyURLTitle
-                                         action:copyURLAction];
-  [self.parentViewController.view endEditing:YES];
-  [self.contextMenuCoordinator start];
-}
-
-- (void)openURL:(const GURL&)URL {
-  new_tab_page_uma::RecordAction(_browserState,
-                                 new_tab_page_uma::ACTION_OPENED_HISTORY_ENTRY);
-  web::NavigationManager::WebLoadParams params(URL);
-  params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
-  [self.delegate historyCollectionViewController:self
-                       shouldCloseWithCompletion:^{
-                         [self.URLLoader loadURLWithParams:params];
-                       }];
-}
-
-- (void)openURLInNewTab:(const GURL&)URL {
-  OpenNewTabCommand* command =
-      [[OpenNewTabCommand alloc] initWithURL:URL
-                                    referrer:web::Referrer()
-                                 inIncognito:NO
-                                inBackground:NO
-                                    appendTo:kLastTab];
-  [self.delegate historyCollectionViewController:self
-                       shouldCloseWithCompletion:^{
-                         [self.URLLoader webPageOrderedOpen:command];
-                       }];
-}
-
-- (void)openURLInNewIncognitoTab:(const GURL&)URL {
-  OpenNewTabCommand* command =
-      [[OpenNewTabCommand alloc] initWithURL:URL
-                                    referrer:web::Referrer()
-                                 inIncognito:YES
-                                inBackground:NO
-                                    appendTo:kLastTab];
-  [self.delegate historyCollectionViewController:self
-                       shouldCloseWithCompletion:^{
-                         [self.URLLoader webPageOrderedOpen:command];
-                       }];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/history/legacy_history_entries_status_item.h b/ios/chrome/browser/ui/history/legacy_history_entries_status_item.h
deleted file mode 100644
index 20b641d8..0000000
--- a/ios/chrome/browser/ui/history/legacy_history_entries_status_item.h
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRIES_STATUS_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRIES_STATUS_ITEM_H_
-
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-
-@class LabelLinkController;
-@protocol HistoryEntriesStatusItemDelegate;
-
-// Model item for HistoryEntriesStatusCell. Manages links added to the cell.
-@interface LegacyHistoryEntriesStatusItem : CollectionViewItem
-// YES if messages should be hidden.
-@property(nonatomic, assign, getter=isHidden) BOOL hidden;
-// Delegate for HistoryEntriesStatusItem. Is notified when a link is pressed.
-@property(nonatomic, weak) id<HistoryEntriesStatusItemDelegate> delegate;
-@end
-
-// Cell for displaying status for history entry. Provides information on whether
-// local or synced entries or displays, and how to access other forms of
-// browsing history, if applicable.
-@interface LegacyHistoryEntriesStatusCell : CollectionViewFooterCell
-@end
-
-@interface LegacyHistoryEntriesStatusCell (Testing)
-// Link controller for entries status message.
-@property(nonatomic, retain, readonly) LabelLinkController* labelLinkController;
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRIES_STATUS_ITEM_H_
diff --git a/ios/chrome/browser/ui/history/legacy_history_entries_status_item.mm b/ios/chrome/browser/ui/history/legacy_history_entries_status_item.mm
deleted file mode 100644
index 09c51cb..0000000
--- a/ios/chrome/browser/ui/history/legacy_history_entries_status_item.mm
+++ /dev/null
@@ -1,126 +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.
-
-#import "ios/chrome/browser/ui/history/legacy_history_entries_status_item.h"
-
-#include "base/mac/foundation_util.h"
-#include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/chrome_url_constants.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
-#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
-#import "ios/chrome/browser/ui/history/history_entries_status_item_delegate.h"
-#import "ios/chrome/browser/ui/util/label_link_controller.h"
-#import "ios/chrome/common/string_util.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-// Delegate for HistoryEntriesStatusCell.
-@protocol HistoryEntriesStatusCellDelegate<NSObject>
-// Notifies the delegate that |URL| should be opened.
-- (void)historyEntriesStatusCell:(LegacyHistoryEntriesStatusCell*)cell
-               didRequestOpenURL:(const GURL&)URL;
-@end
-
-@interface LegacyHistoryEntriesStatusCell ()
-// Redeclare as readwrite.
-@property(nonatomic, strong, readwrite)
-    LabelLinkController* labelLinkController;
-// Delegate for the HistoryEntriesStatusCell. Is notified when a link is
-// tapped.
-@property(nonatomic, weak) id<HistoryEntriesStatusCellDelegate> delegate;
-// Sets the browsing data url link on the cell label.
-- (void)setLinkForBrowsingDataURL:(const GURL&)browsingDataURL;
-@end
-
-@interface LegacyHistoryEntriesStatusItem ()<HistoryEntriesStatusCellDelegate>
-@end
-
-@implementation LegacyHistoryEntriesStatusItem
-@synthesize delegate = _delegate;
-@synthesize hidden = _hidden;
-
-- (Class)cellClass {
-  return [LegacyHistoryEntriesStatusCell class];
-}
-
-- (void)configureCell:(LegacyHistoryEntriesStatusCell*)cell {
-  [super configureCell:cell];
-  [cell setDelegate:self];
-  if (self.hidden) {
-    cell.textLabel.text = nil;
-  } else {
-    cell.textLabel.text =
-        l10n_util::GetNSString(IDS_IOS_HISTORY_OTHER_FORMS_OF_HISTORY);
-    ;
-    [cell setLinkForBrowsingDataURL:GURL(kHistoryMyActivityURL)];
-  }
-}
-
-- (void)historyEntriesStatusCell:(LegacyHistoryEntriesStatusCell*)cell
-               didRequestOpenURL:(const GURL&)URL {
-  [self.delegate historyEntriesStatusItem:self didRequestOpenURL:URL];
-}
-
-- (BOOL)isEqualToHistoryEntriesStatusItem:
-    (LegacyHistoryEntriesStatusItem*)object {
-  return self.hidden == object.hidden;
-}
-
-- (BOOL)isEqual:(id)object {
-  if (self == object) {
-    return YES;
-  }
-  if (![object isKindOfClass:[LegacyHistoryEntriesStatusItem class]]) {
-    return NO;
-  }
-  return [self
-      isEqualToHistoryEntriesStatusItem:base::mac::ObjCCastStrict<
-                                            LegacyHistoryEntriesStatusItem>(
-                                            object)];
-}
-
-@end
-
-@implementation LegacyHistoryEntriesStatusCell
-@synthesize delegate = _delegate;
-@synthesize labelLinkController = _labelLinkController;
-
-- (void)setLinkForBrowsingDataURL:(const GURL&)browsingDataURL {
-  __weak LegacyHistoryEntriesStatusCell* weakSelf = self;
-  self.labelLinkController = [[LabelLinkController alloc]
-      initWithLabel:self.textLabel
-             action:^(const GURL& URL) {
-               [[weakSelf delegate] historyEntriesStatusCell:weakSelf
-                                           didRequestOpenURL:URL];
-             }];
-  [self.labelLinkController setLinkColor:[[MDCPalette cr_bluePalette] tint500]];
-
-  // Remove link delimiter from text and get ranges for links. Must be parsed
-  // before being added to the controller because modifying the label text
-  // clears all added links.
-  NSRange otherBrowsingDataRange;
-  if (browsingDataURL.is_valid()) {
-    self.textLabel.text =
-        ParseStringWithLink(self.textLabel.text, &otherBrowsingDataRange);
-    DCHECK(otherBrowsingDataRange.location != NSNotFound &&
-           otherBrowsingDataRange.length);
-
-    [self.labelLinkController addLinkWithRange:otherBrowsingDataRange
-                                           url:browsingDataURL];
-  }
-}
-
-- (void)prepareForReuse {
-  [super prepareForReuse];
-  self.labelLinkController = nil;
-  self.delegate = nil;
-}
-
-@end
diff --git a/ios/chrome/browser/ui/history/legacy_history_entries_status_item_unittest.mm b/ios/chrome/browser/ui/history/legacy_history_entries_status_item_unittest.mm
deleted file mode 100644
index ffd3e534..0000000
--- a/ios/chrome/browser/ui/history/legacy_history_entries_status_item_unittest.mm
+++ /dev/null
@@ -1,95 +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.
-
-#import "ios/chrome/browser/ui/history/legacy_history_entries_status_item.h"
-
-#import "base/test/ios/wait_util.h"
-#include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/chrome_url_constants.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
-#import "ios/chrome/browser/ui/history/history_entries_status_item_delegate.h"
-#import "ios/chrome/browser/ui/util/label_link_controller.h"
-#import "ios/chrome/common/string_util.h"
-#include "ios/chrome/grit/ios_strings.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#import "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-#include "third_party/ocmock/OCMock/OCMock.h"
-#include "third_party/ocmock/gtest_support.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-#include "url/gurl.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-// Mock delegate for HistoryEntriesStatusItem. Implement mock delegate rather
-// than use OCMock because delegate method takes a GURL as a parameter.
-@interface MockEntriesStatusItemDelegate
-    : NSObject<HistoryEntriesStatusItemDelegate>
-@property(nonatomic) BOOL delegateCalledForSyncURL;
-@property(nonatomic) BOOL delegateCalledForBrowsingDataURL;
-@end
-
-@implementation MockEntriesStatusItemDelegate
-@synthesize delegateCalledForSyncURL = _delegateCalledForSyncURL;
-@synthesize delegateCalledForBrowsingDataURL =
-    _delegateCalledForBrowsingDataURL;
-- (void)historyEntriesStatusItem:(LegacyHistoryEntriesStatusItem*)item
-               didRequestOpenURL:(const GURL&)URL {
-  GURL browsingDataURL(kHistoryMyActivityURL);
-  if (URL == browsingDataURL) {
-    self.delegateCalledForBrowsingDataURL = YES;
-  }
-}
-@end
-
-namespace {
-
-using LegacyHistoryEntriesStatusItemTest = PlatformTest;
-
-// Tests that configuring a cell for HistoryEntriesStatusItem with hidden
-// property set to YES results in an empty label.
-TEST_F(LegacyHistoryEntriesStatusItemTest, TestHidden) {
-  LegacyHistoryEntriesStatusItem* item =
-      [[LegacyHistoryEntriesStatusItem alloc] initWithType:0];
-  item.hidden = YES;
-  LegacyHistoryEntriesStatusCell* cell =
-      [[LegacyHistoryEntriesStatusCell alloc] init];
-  [item configureCell:cell];
-  EXPECT_FALSE(cell.textLabel.text);
-}
-
-// Tests that tapping on links on a configured cell invokes
-// the HistoryEntriesStatusItemDelegate method.
-TEST_F(LegacyHistoryEntriesStatusItemTest, TestDelegate) {
-  LegacyHistoryEntriesStatusItem* item =
-      [[LegacyHistoryEntriesStatusItem alloc] initWithType:0];
-  LegacyHistoryEntriesStatusCell* cell =
-      [[LegacyHistoryEntriesStatusCell alloc] init];
-  MockEntriesStatusItemDelegate* delegate =
-      [[MockEntriesStatusItemDelegate alloc] init];
-  item.delegate = delegate;
-  item.hidden = NO;
-  [item configureCell:cell];
-
-  // Layout the cell so that links are drawn.
-  cell.frame = CGRectMake(0, 0, 360, 100);
-  [cell setNeedsLayout];
-  [cell layoutIfNeeded];
-
-  // Tap link for more info on browsing data.
-  GURL browsing_data_url(kHistoryMyActivityURL);
-  CGRect browsing_data_rect = [[[cell.labelLinkController
-      tapRectsForURL:browsing_data_url] objectAtIndex:0] CGRectValue];
-  [cell.labelLinkController
-      tapLabelAtPoint:CGPointMake(CGRectGetMidX(browsing_data_rect),
-                                  CGRectGetMidY(browsing_data_rect))];
-
-  base::test::ios::WaitUntilCondition(^bool() {
-    return delegate.delegateCalledForBrowsingDataURL;
-  });
-}
-}  // namespace
diff --git a/ios/chrome/browser/ui/history/legacy_history_entry_item.h b/ios/chrome/browser/ui/history/legacy_history_entry_item.h
deleted file mode 100644
index 7c992cb..0000000
--- a/ios/chrome/browser/ui/history/legacy_history_entry_item.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRY_ITEM_H_
-#define IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRY_ITEM_H_
-
-#include "components/history/core/browser/browsing_history_service.h"
-#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
-#import "ios/chrome/browser/ui/history/history_entry_item_interface.h"
-#import "ios/third_party/material_components_ios/src/components/Collections/src/MaterialCollections.h"
-
-namespace ios {
-class ChromeBrowserState;
-}  // namespace ios
-
-@class FaviconView;
-@protocol FaviconViewProviderDelegate;
-@protocol HistoryEntryItemDelegate;
-
-// Model object for the cell that displays a history entry.
-@interface LegacyHistoryEntryItem
-    : CollectionViewItem<HistoryEntryItemInterface>
-
-// The |delegate| is notified when the favicon has loaded, and may be nil.
-- (instancetype)initWithType:(NSInteger)type
-                historyEntry:
-                    (const history::BrowsingHistoryService::HistoryEntry&)entry
-                browserState:(ios::ChromeBrowserState*)browserState
-                    delegate:(id<HistoryEntryItemDelegate>)delegate
-    NS_DESIGNATED_INITIALIZER;
-- (instancetype)initWithType:(NSInteger)type NS_UNAVAILABLE;
-
-@end
-
-// Cell that renders a history entry.
-@interface LegacyHistoryEntryCell : MDCCollectionViewCell
-
-// View for displaying the favicon for the history entry.
-@property(nonatomic, strong) UIView* faviconViewContainer;
-// Text label for history entry title.
-@property(nonatomic, readonly, strong) UILabel* textLabel;
-// Text label for history entry URL.
-@property(nonatomic, readonly, strong) UILabel* detailTextLabel;
-// Text label for history entry timestamp.
-@property(nonatomic, readonly, strong) UILabel* timeLabel;
-
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_HISTORY_LEGACY_HISTORY_ENTRY_ITEM_H_
diff --git a/ios/chrome/browser/ui/history/legacy_history_entry_item.mm b/ios/chrome/browser/ui/history/legacy_history_entry_item.mm
deleted file mode 100644
index 494a6bce..0000000
--- a/ios/chrome/browser/ui/history/legacy_history_entry_item.mm
+++ /dev/null
@@ -1,286 +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.
-
-#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h"
-
-#include "base/i18n/time_formatting.h"
-#import "base/mac/foundation_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/history/core/browser/url_row.h"
-#include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
-#import "ios/chrome/browser/ui/history/favicon_view.h"
-#import "ios/chrome/browser/ui/history/favicon_view_provider.h"
-#import "ios/chrome/browser/ui/history/history_entry_item_delegate.h"
-#include "ios/chrome/browser/ui/history/history_util.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"
-#import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
-#import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
-#include "ui/base/l10n/l10n_util.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-namespace {
-// Size at which the favicon will be displayed.
-const CGFloat kFaviconSize = 24.0;
-// Minimum size at which to fetch favicons.
-const CGFloat kMinFaviconSize = 16.0;
-// Horizontal spacing between edge of the cell and the cell content.
-const CGFloat kMargin = 16.0;
-// Horizontal spacing between the leading edge of the cell and the text.
-const CGFloat kHeaderMargin = 56.0;
-}  // namespace
-
-#pragma mark - LegacyHistoryEntryItem
-
-@interface LegacyHistoryEntryItem ()<FaviconViewProviderDelegate> {
-  // Delegate for LegacyHistoryEntryItem.
-  __weak id<HistoryEntryItemDelegate> _delegate;
-}
-
-// FaviconViewProvider to fetch the favicon and format the favicon view.
-@property(nonatomic, strong) FaviconViewProvider* faviconViewProvider;
-
-// Custom accessibility actions for the history entry view.
-- (NSArray*)accessibilityActions;
-// Custom accessibility action to delete the history entry.
-- (BOOL)deleteHistoryEntry;
-// Custom accessibility action to open the history entry's URL in a new tab.
-- (BOOL)openInNewTab;
-// Custom accessibility action to open the history entry's URL in a new
-// incognito tab.
-- (BOOL)openInNewIncognitoTab;
-// Custom accessibility action to copy the history entry's URL to the clipboard.
-- (BOOL)copyURL;
-@end
-
-@implementation LegacyHistoryEntryItem
-
-@synthesize faviconViewProvider = _faviconViewProvider;
-@synthesize text = _text;
-@synthesize detailText = _detailText;
-@synthesize timeText = _timeText;
-@synthesize URL = _URL;
-@synthesize timestamp = _timestamp;
-
-- (instancetype)initWithType:(NSInteger)type
-                historyEntry:
-                    (const history::BrowsingHistoryService::HistoryEntry&)entry
-                browserState:(ios::ChromeBrowserState*)browserState
-                    delegate:(id<HistoryEntryItemDelegate>)delegate {
-  self = [super initWithType:type];
-  if (self) {
-    self.cellClass = [LegacyHistoryEntryCell class];
-    favicon::LargeIconService* largeIconService =
-        IOSChromeLargeIconServiceFactory::GetForBrowserState(browserState);
-    _faviconViewProvider =
-        [[FaviconViewProvider alloc] initWithURL:entry.url
-                                     faviconSize:kFaviconSize
-                                  minFaviconSize:kMinFaviconSize
-                                largeIconService:largeIconService
-                                        delegate:self];
-    _text = [history::FormattedTitle(entry.title, entry.url) copy];
-    _detailText = [base::SysUTF8ToNSString(entry.url.spec()) copy];
-    _timeText =
-        [base::SysUTF16ToNSString(base::TimeFormatTimeOfDay(entry.time)) copy];
-    _URL = GURL(entry.url);
-    _timestamp = entry.time;
-    _delegate = delegate;
-  }
-  return self;
-}
-
-- (instancetype)initWithType:(NSInteger)type {
-  NOTREACHED();
-  return nil;
-}
-
-- (BOOL)isEqualToHistoryEntryItem:(id<HistoryEntryItemInterface>)item {
-  return item && item.URL == _URL && item.timestamp == _timestamp;
-}
-
-- (BOOL)isEqual:(id)object {
-  if (self == object)
-    return YES;
-
-  if (![object isMemberOfClass:[LegacyHistoryEntryItem class]])
-    return NO;
-
-  return [self isEqualToHistoryEntryItem:object];
-}
-
-- (NSUInteger)hash {
-  return [base::SysUTF8ToNSString(self.URL.spec()) hash] ^
-         self.timestamp.ToInternalValue();
-}
-
-- (NSArray*)accessibilityActions {
-  UIAccessibilityCustomAction* deleteAction =
-      [[UIAccessibilityCustomAction alloc]
-          initWithName:l10n_util::GetNSString(
-                           IDS_HISTORY_ENTRY_ACCESSIBILITY_DELETE)
-                target:self
-              selector:@selector(deleteHistoryEntry)];
-  UIAccessibilityCustomAction* openInNewTabAction =
-      [[UIAccessibilityCustomAction alloc]
-          initWithName:l10n_util::GetNSString(
-                           IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWTAB)
-                target:self
-              selector:@selector(openInNewTab)];
-  UIAccessibilityCustomAction* openInNewIncognitoTabAction =
-      [[UIAccessibilityCustomAction alloc]
-          initWithName:l10n_util::GetNSString(
-                           IDS_IOS_CONTENT_CONTEXT_OPENLINKNEWINCOGNITOTAB)
-                target:self
-              selector:@selector(openInNewIncognitoTab)];
-  UIAccessibilityCustomAction* copyURLAction =
-      [[UIAccessibilityCustomAction alloc]
-          initWithName:l10n_util::GetNSString(IDS_IOS_CONTENT_CONTEXT_COPY)
-                target:self
-              selector:@selector(copyURL)];
-  return @[
-    deleteAction, openInNewTabAction, openInNewIncognitoTabAction, copyURLAction
-  ];
-}
-
-- (BOOL)deleteHistoryEntry {
-  [_delegate historyEntryItemDidRequestDelete:self];
-  return YES;
-}
-
-- (BOOL)openInNewTab {
-  [_delegate historyEntryItemDidRequestOpenInNewTab:self];
-  return YES;
-}
-
-- (BOOL)openInNewIncognitoTab {
-  [_delegate historyEntryItemDidRequestOpenInNewIncognitoTab:self];
-  return YES;
-}
-
-- (BOOL)copyURL {
-  [_delegate historyEntryItemDidRequestCopy:self];
-  return YES;
-}
-
-- (void)configureCell:(LegacyHistoryEntryCell*)cell {
-  [super configureCell:cell];
-
-  // Set favicon view and constraints.
-  FaviconView* faviconView = self.faviconViewProvider.faviconView;
-  [cell.faviconViewContainer addSubview:faviconView];
-  [faviconView setTranslatesAutoresizingMaskIntoConstraints:NO];
-  AddSameConstraints(faviconView, cell.faviconViewContainer);
-
-  cell.textLabel.text = self.text;
-  cell.detailTextLabel.text = self.detailText;
-  cell.timeLabel.text = self.timeText;
-  cell.isAccessibilityElement = YES;
-  cell.accessibilityCustomActions = self.accessibilityActions;
-  cell.accessibilityLabel =
-      l10n_util::GetNSStringF(IDS_HISTORY_ENTRY_ACCESSIBILITY_LABEL,
-                              base::SysNSStringToUTF16(self.text),
-                              base::SysNSStringToUTF16(self.detailText),
-                              base::SysNSStringToUTF16(self.timeText));
-}
-
-- (void)faviconViewProviderFaviconDidLoad:(FaviconViewProvider*)provider {
-  [_delegate historyEntryItemShouldUpdateView:self];
-}
-
-@end
-
-#pragma mark - LegacyHistoryEntryCell
-
-@interface LegacyHistoryEntryCell ()
-
-// Redeclare as readwrite.
-@property(nonatomic, readwrite, strong) UILabel* textLabel;
-@property(nonatomic, readwrite, strong) UILabel* detailTextLabel;
-@property(nonatomic, readwrite, strong) UILabel* timeLabel;
-@end
-
-@implementation LegacyHistoryEntryCell
-
-@synthesize faviconViewContainer = _faviconViewContainer;
-@synthesize textLabel = _textLabel;
-@synthesize detailTextLabel = _detailTextLabel;
-@synthesize timeLabel = _timeLabel;
-
-- (id)initWithFrame:(CGRect)frame {
-  self = [super initWithFrame:frame];
-  if (self) {
-    _faviconViewContainer = [[UIView alloc] initWithFrame:CGRectZero];
-
-    _textLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    [_textLabel setFont:[[MDCTypography fontLoader] mediumFontOfSize:16]];
-    [_textLabel setTextColor:[[MDCPalette greyPalette] tint900]];
-
-    _detailTextLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    [_detailTextLabel
-        setFont:[[MDCTypography fontLoader] regularFontOfSize:14]];
-    [_detailTextLabel setTextColor:[[MDCPalette greyPalette] tint600]];
-
-    _timeLabel = [[UILabel alloc] initWithFrame:CGRectZero];
-    [_timeLabel setFont:[[MDCTypography fontLoader] mediumFontOfSize:14]];
-    [_timeLabel setTextColor:[[MDCPalette greyPalette] tint600]];
-    _timeLabel.textAlignment =
-        UseRTLLayout() ? NSTextAlignmentLeft : NSTextAlignmentRight;
-
-    UIView* contentView = self.contentView;
-    [contentView addSubview:_faviconViewContainer];
-    [contentView addSubview:_textLabel];
-    [contentView addSubview:_detailTextLabel];
-    [contentView addSubview:_timeLabel];
-
-    [_faviconViewContainer setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [_textLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [_detailTextLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
-    [_timeLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
-
-    [_faviconViewContainer.widthAnchor constraintEqualToConstant:kFaviconSize];
-
-    NSDictionary* views = @{
-      @"title" : _textLabel,
-      @"URL" : _detailTextLabel,
-      @"time" : _timeLabel,
-      @"favicon" : _faviconViewContainer,
-    };
-    NSDictionary* metrics = @{
-      @"margin" : @(kMargin),
-      @"spacing" : @(kHeaderMargin - (kMargin + kFaviconSize)),
-    };
-    NSArray* constraints = @[
-      @"H:|-margin-[favicon]-spacing-[title]-[time]-margin-|",
-      @"H:|-margin-[favicon]-spacing-[URL]-margin-|",
-      @"V:|-margin-[title][URL]-margin-|",
-    ];
-    ApplyVisualConstraintsWithMetrics(constraints, views, metrics);
-    AddSameCenterYConstraint(_textLabel, _timeLabel);
-    AddSameCenterYConstraint(_faviconViewContainer, _textLabel);
-
-    [_timeLabel
-        setContentCompressionResistancePriority:UILayoutPriorityRequired
-                                        forAxis:
-                                            UILayoutConstraintAxisHorizontal];
-  }
-  return self;
-}
-
-- (void)prepareForReuse {
-  [super prepareForReuse];
-  _textLabel.text = nil;
-  _detailTextLabel.text = nil;
-  _timeLabel.text = nil;
-  for (UIView* subview in _faviconViewContainer.subviews) {
-    [subview removeFromSuperview];
-  }
-}
-
-@end
diff --git a/ios/chrome/browser/ui/history/legacy_history_entry_item_unittest.mm b/ios/chrome/browser/ui/history/legacy_history_entry_item_unittest.mm
deleted file mode 100644
index 72ab6e5a..0000000
--- a/ios/chrome/browser/ui/history/legacy_history_entry_item_unittest.mm
+++ /dev/null
@@ -1,79 +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.
-
-#import "ios/chrome/browser/ui/history/legacy_history_entry_item.h"
-
-#include "base/i18n/time_formatting.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/time/time.h"
-#include "components/history/core/browser/browsing_history_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gtest_mac.h"
-#include "testing/platform_test.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-using history::BrowsingHistoryService;
-
-namespace {
-const char kTestUrl[] = "http://test/";
-const char kTestUrl2[] = "http://test2/";
-const char kTestTitle[] = "Test";
-}
-
-LegacyHistoryEntryItem* GetHistoryEntryItem(const GURL& url,
-                                            const char title[],
-                                            base::Time timestamp) {
-  BrowsingHistoryService::HistoryEntry entry(
-      BrowsingHistoryService::HistoryEntry::LOCAL_ENTRY, GURL(url),
-      base::UTF8ToUTF16(title), timestamp, "", false, base::string16(), false);
-  LegacyHistoryEntryItem* item =
-      [[LegacyHistoryEntryItem alloc] initWithType:0
-                                      historyEntry:entry
-                                      browserState:nil
-                                          delegate:nil];
-  return item;
-}
-
-using LegacyHistoryEntryItemTest = PlatformTest;
-
-// Tests that -[HistoryEntryItem configureCell:] sets the cell's textLabel text
-// to the item title, the detailTextLabel text to the URL, and the timeLabel
-// text to the timestamp.
-TEST_F(LegacyHistoryEntryItemTest, ConfigureCell) {
-  base::Time timestamp = base::Time::Now();
-  LegacyHistoryEntryItem* item =
-      GetHistoryEntryItem(GURL(kTestUrl), kTestTitle, timestamp);
-
-  LegacyHistoryEntryCell* cell = [[[item cellClass] alloc] init];
-  EXPECT_TRUE([cell isMemberOfClass:[LegacyHistoryEntryCell class]]);
-  [item configureCell:cell];
-  EXPECT_NSEQ(base::SysUTF8ToNSString(kTestTitle), cell.textLabel.text);
-  EXPECT_NSEQ(base::SysUTF8ToNSString(kTestUrl), cell.detailTextLabel.text);
-  EXPECT_NSEQ(base::SysUTF16ToNSString(base::TimeFormatTimeOfDay(timestamp)),
-              cell.timeLabel.text);
-}
-
-// Tests that -[HistoryItem isEqualToHistoryItem:] returns YES if the two items
-// have the same URL and timestamp, and NO otherwise.
-TEST_F(LegacyHistoryEntryItemTest, IsEqual) {
-  base::Time timestamp = base::Time::Now();
-  base::Time timestamp2 = timestamp - base::TimeDelta::FromMinutes(1);
-  LegacyHistoryEntryItem* history_entry =
-      GetHistoryEntryItem(GURL(kTestUrl), kTestTitle, timestamp);
-  LegacyHistoryEntryItem* same_entry =
-      GetHistoryEntryItem(GURL(kTestUrl), kTestTitle, timestamp);
-
-  LegacyHistoryEntryItem* different_time_entry =
-      GetHistoryEntryItem(GURL(kTestUrl), kTestTitle, timestamp2);
-  LegacyHistoryEntryItem* different_url_entry =
-      GetHistoryEntryItem(GURL(kTestUrl2), kTestTitle, timestamp);
-
-  EXPECT_TRUE([history_entry isEqual:same_entry]);
-  EXPECT_FALSE([history_entry isEqual:different_time_entry]);
-  EXPECT_FALSE([history_entry isEqual:different_url_entry]);
-}
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
index 095878b..b4d50b2 100644
--- a/ios/chrome/browser/ui/main/BUILD.gn
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -10,8 +10,6 @@
     "browser_view_wrangler.mm",
     "bvc_container_view_controller.h",
     "bvc_container_view_controller.mm",
-    "main_containing_view_controller.h",
-    "main_containing_view_controller.mm",
     "main_coordinator.h",
     "main_coordinator.mm",
     "main_presenting_view_controller.h",
@@ -19,7 +17,6 @@
     "view_controller_swapping.h",
   ]
   deps = [
-    ":feature_flags",
     ":tab_switcher",
     "//base",
     "//ios/chrome/app/resources:launchscreen_xib",
@@ -41,17 +38,6 @@
   libs = [ "UIKit.framework" ]
 }
 
-source_set("feature_flags") {
-  configs += [ "//build/config/compiler:enable_arc" ]
-  sources = [
-    "main_feature_flags.cc",
-    "main_feature_flags.h",
-  ]
-  deps = [
-    "//base",
-  ]
-}
-
 source_set("tab_switcher") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
@@ -71,7 +57,6 @@
   testonly = true
   sources = [
     "browser_view_wrangler_unittest.mm",
-    "main_containing_view_controller_unittest.mm",
     "main_coordinator_unittest.mm",
     "main_presenting_view_controller_unittest.mm",
   ]
diff --git a/ios/chrome/browser/ui/main/main_containing_view_controller.h b/ios/chrome/browser/ui/main/main_containing_view_controller.h
deleted file mode 100644
index 4478138bb..0000000
--- a/ios/chrome/browser/ui/main/main_containing_view_controller.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_MAIN_MAIN_CONTAINING_VIEW_CONTROLLER_H_
-#define IOS_CHROME_BROWSER_UI_MAIN_MAIN_CONTAINING_VIEW_CONTROLLER_H_
-
-#import "ios/chrome/browser/ui/main/view_controller_swapping.h"
-
-// A UIViewController that uses containment to display TabSwitchers and
-// BrowserViewControllers..
-@interface MainContainingViewController
-    : UIViewController<ViewControllerSwapping>
-@end
-
-#endif  // IOS_CHROME_BROWSER_UI_MAIN_MAIN_CONTAINING_VIEW_CONTROLLER_H_
diff --git a/ios/chrome/browser/ui/main/main_containing_view_controller.mm b/ios/chrome/browser/ui/main/main_containing_view_controller.mm
deleted file mode 100644
index 00e825ec..0000000
--- a/ios/chrome/browser/ui/main/main_containing_view_controller.mm
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/main/main_containing_view_controller.h"
-
-#import "base/logging.h"
-#import "ios/chrome/browser/ui/main/tab_switcher.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@implementation MainContainingViewController
-
-- (UIViewController*)activeViewController {
-  return [self.childViewControllers firstObject];
-}
-
-- (UIViewController*)viewController {
-  return self;
-}
-
-- (void)showTabSwitcher:(id<TabSwitcher>)tabSwitcher
-             completion:(ProceduralBlock)completion {
-  [self setActiveViewController:[tabSwitcher viewController]
-                     completion:completion];
-  [tabSwitcher showWithSelectedTabAnimation];
-}
-
-- (void)showTabViewController:(UIViewController*)viewController
-                   completion:(ProceduralBlock)completion {
-  [self setActiveViewController:viewController completion:completion];
-}
-
-// Swaps in and displays the given view controller, replacing any other
-// view controllers that may currently be visible.  Runs
-// the given |completion| block after the view controller is visible.
-- (void)setActiveViewController:(UIViewController*)activeViewController
-                     completion:(void (^)())completion {
-  DCHECK(activeViewController);
-  if (self.activeViewController == activeViewController) {
-    if (completion) {
-      completion();
-    }
-    return;
-  }
-
-  // TODO(crbug.com/546189): DCHECK here that there isn't a modal view
-  // controller showing once the known violations of that are fixed.
-
-  // Remove the current active view controller, if any.
-  if (self.activeViewController) {
-    [self.activeViewController willMoveToParentViewController:nil];
-    [self.activeViewController.view removeFromSuperview];
-    [self.activeViewController removeFromParentViewController];
-  }
-
-  DCHECK_EQ(nil, self.activeViewController);
-  DCHECK_EQ(0U, self.view.subviews.count);
-
-  // Add the new active view controller.
-  [self addChildViewController:activeViewController];
-  self.activeViewController.view.frame = self.view.bounds;
-  [self.view addSubview:self.activeViewController.view];
-  [activeViewController didMoveToParentViewController:self];
-
-  // Let the system know that the child has changed so appearance updates can
-  // be made.
-  [self setNeedsStatusBarAppearanceUpdate];
-
-  DCHECK(self.activeViewController == activeViewController);
-  if (completion) {
-    completion();
-  }
-}
-
-#pragma mark - UIViewController methods
-
-- (void)presentViewController:(UIViewController*)viewControllerToPresent
-                     animated:(BOOL)flag
-                   completion:(void (^)())completion {
-  // If there is no activeViewController then this call will get inadvertently
-  // dropped.
-  DCHECK(self.activeViewController);
-  [self.activeViewController presentViewController:viewControllerToPresent
-                                          animated:flag
-                                        completion:completion];
-}
-
-- (void)dismissViewControllerAnimated:(BOOL)flag
-                           completion:(void (^)())completion {
-  // If there is no activeViewController then this call will get inadvertently
-  // dropped.
-  DCHECK(self.activeViewController);
-  [self.activeViewController dismissViewControllerAnimated:flag
-                                                completion:completion];
-}
-
-- (UIViewController*)childViewControllerForStatusBarHidden {
-  return self.activeViewController;
-}
-
-- (UIViewController*)childViewControllerForStatusBarStyle {
-  return self.activeViewController;
-}
-
-- (BOOL)shouldAutorotate {
-  return self.activeViewController
-             ? [self.activeViewController shouldAutorotate]
-             : [super shouldAutorotate];
-}
-
-@end
diff --git a/ios/chrome/browser/ui/main/main_containing_view_controller_unittest.mm b/ios/chrome/browser/ui/main/main_containing_view_controller_unittest.mm
deleted file mode 100644
index c569b9a..0000000
--- a/ios/chrome/browser/ui/main/main_containing_view_controller_unittest.mm
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/chrome/browser/ui/main/main_containing_view_controller.h"
-
-#import <UIKit/UIKit.h>
-
-#import "base/test/ios/wait_util.h"
-#include "base/test/scoped_feature_list.h"
-#import "ios/chrome/browser/ui/main/main_view_controller_test.h"
-#import "ios/chrome/browser/ui/main/tab_switcher.h"
-#import "ios/chrome/test/block_cleanup_test.h"
-#include "testing/gtest_mac.h"
-
-#if !defined(__has_feature) || !__has_feature(objc_arc)
-#error "This file requires ARC support."
-#endif
-
-@interface HiddenStatusBarViewController : UIViewController
-@end
-
-@implementation HiddenStatusBarViewController
-- (BOOL)prefersStatusBarHidden {
-  return YES;
-}
-@end
-
-@interface MockViewController : UIViewController
-@property(nonatomic, readonly) NSInteger didMoveToParentViewControllerCount;
-@property(nonatomic, weak, readonly) id didMoveToParentViewControllerArgument;
-@property(nonatomic, readonly) NSInteger willMoveToParentViewControllerCount;
-@property(nonatomic, weak, readonly) id willMoveToParentViewControllerArgument;
-@end
-
-@implementation MockViewController
-@synthesize didMoveToParentViewControllerCount =
-    _didMoveToParentViewControllerCount;
-@synthesize didMoveToParentViewControllerArgument =
-    _didMoveToParentViewControllerArgument;
-@synthesize willMoveToParentViewControllerCount =
-    _willMoveToParentViewControllerCount;
-@synthesize willMoveToParentViewControllerArgument =
-    _willMoveToParentViewControllerArgument;
-
-- (void)didMoveToParentViewController:(UIViewController*)parent {
-  _didMoveToParentViewControllerCount++;
-  _didMoveToParentViewControllerArgument = parent;
-}
-
-- (void)willMoveToParentViewController:(UIViewController*)parent {
-  _willMoveToParentViewControllerCount++;
-  _willMoveToParentViewControllerArgument = parent;
-}
-
-@end
-
-namespace {
-
-using MainContainingViewControllerTest = MainViewControllerTest;
-
-TEST_F(MainContainingViewControllerTest, ActiveVC) {
-  MainContainingViewController* main_view_controller =
-      [[MainContainingViewController alloc] init];
-  id<TabSwitcher> child_tab_switcher_1 = CreateTestTabSwitcher();
-  id<TabSwitcher> child_tab_switcher_2 = CreateTestTabSwitcher();
-
-  // Test that the active view controller is always the first child view
-  // controller.
-  EXPECT_EQ(nil, [main_view_controller activeViewController]);
-  [main_view_controller
-      addChildViewController:[child_tab_switcher_1 viewController]];
-  EXPECT_EQ([child_tab_switcher_1 viewController],
-            [main_view_controller activeViewController]);
-  [main_view_controller
-      addChildViewController:[child_tab_switcher_2 viewController]];
-  EXPECT_EQ([child_tab_switcher_1 viewController],
-            [main_view_controller activeViewController]);
-  [[child_tab_switcher_1 viewController] removeFromParentViewController];
-  EXPECT_EQ([child_tab_switcher_2 viewController],
-            [main_view_controller activeViewController]);
-}
-
-TEST_F(MainContainingViewControllerTest, Setters) {
-  MainContainingViewController* main_view_controller =
-      [[MainContainingViewController alloc] init];
-  CGRect windowRect = CGRectMake(0, 0, 200, 200);
-  [main_view_controller view].frame = windowRect;
-
-  MockViewController* child_view_controller = [[MockViewController alloc] init];
-  child_view_controller.view.frame = CGRectMake(0, 0, 10, 10);
-
-  [main_view_controller showTabViewController:child_view_controller
-                                   completion:nil];
-  EXPECT_EQ(child_view_controller,
-            [[main_view_controller childViewControllers] firstObject]);
-  EXPECT_EQ(child_view_controller.view,
-            [[main_view_controller view].subviews firstObject]);
-  EXPECT_NSEQ(NSStringFromCGRect(windowRect),
-              NSStringFromCGRect(child_view_controller.view.frame));
-  EXPECT_EQ(1, [child_view_controller didMoveToParentViewControllerCount]);
-  EXPECT_EQ(main_view_controller,
-            [child_view_controller didMoveToParentViewControllerArgument]);
-  // Expect there to have also been an automatic call to
-  // -willMoveToParentViewController.
-  EXPECT_EQ(1, [child_view_controller willMoveToParentViewControllerCount]);
-  EXPECT_EQ(main_view_controller,
-            [child_view_controller willMoveToParentViewControllerArgument]);
-
-  id<TabSwitcher> child_tab_switcher = CreateTestTabSwitcher();
-  [main_view_controller showTabSwitcher:child_tab_switcher completion:nil];
-  EXPECT_EQ([child_tab_switcher viewController],
-            [[main_view_controller childViewControllers] firstObject]);
-  EXPECT_EQ(1U, [[main_view_controller childViewControllers] count]);
-  EXPECT_EQ(nil, [child_view_controller.view superview]);
-  EXPECT_EQ(2, [child_view_controller willMoveToParentViewControllerCount]);
-  EXPECT_EQ(nil,
-            [child_view_controller willMoveToParentViewControllerArgument]);
-  // Expect there to have also been an automatic call to
-  // -didMoveToParentViewController.
-  EXPECT_EQ(2, [child_view_controller willMoveToParentViewControllerCount]);
-  EXPECT_EQ(nil, [child_view_controller didMoveToParentViewControllerArgument]);
-}
-
-TEST_F(MainContainingViewControllerTest, StatusBar) {
-  MainContainingViewController* main_view_controller =
-      [[MainContainingViewController alloc] init];
-  SetRootViewController(main_view_controller);
-
-  id<TabSwitcher> status_bar_visible_tab_switcher = CreateTestTabSwitcher();
-  [main_view_controller showTabSwitcher:status_bar_visible_tab_switcher
-                             completion:nil];
-  // Check if the status bar is hidden by testing if the status bar rect is
-  // CGRectZero.
-  EXPECT_FALSE(CGRectEqualToRect(
-      [UIApplication sharedApplication].statusBarFrame, CGRectZero));
-  HiddenStatusBarViewController* status_bar_hidden_view_controller =
-      [[HiddenStatusBarViewController alloc] init];
-  [main_view_controller showTabViewController:status_bar_hidden_view_controller
-                                   completion:nil];
-  EXPECT_EQ([main_view_controller childViewControllerForStatusBarHidden],
-            status_bar_hidden_view_controller);
-  EXPECT_TRUE(CGRectEqualToRect(
-      [UIApplication sharedApplication].statusBarFrame, CGRectZero));
-}
-
-// Tests that completion handlers are called properly after the new view
-// controller is made active
-TEST_F(MainContainingViewControllerTest, CompletionHandlers) {
-  MainContainingViewController* main_view_controller =
-      [[MainContainingViewController alloc] init];
-  CGRect windowRect = CGRectMake(0, 0, 200, 200);
-  [main_view_controller view].frame = windowRect;
-
-  id<TabSwitcher> child_tab_switcher_1 = CreateTestTabSwitcher();
-  [[child_tab_switcher_1 viewController] view].frame = CGRectMake(0, 0, 10, 10);
-
-  id<TabSwitcher> child_tab_switcher_2 = CreateTestTabSwitcher();
-  [[child_tab_switcher_2 viewController] view].frame =
-      CGRectMake(20, 20, 10, 10);
-
-  // Tests that the completion handler is called when there is no preexisting
-  // active view controller.
-  __block BOOL completion_handler_was_called = false;
-  [main_view_controller showTabSwitcher:child_tab_switcher_1
-                             completion:^{
-                               completion_handler_was_called = YES;
-                             }];
-  base::test::ios::WaitUntilCondition(^bool() {
-    return completion_handler_was_called;
-  });
-  ASSERT_TRUE(completion_handler_was_called);
-
-  // Tests that the completion handler is called when replacing an existing
-  // active view controller.
-  completion_handler_was_called = NO;
-  [main_view_controller showTabSwitcher:child_tab_switcher_2
-                             completion:^{
-                               completion_handler_was_called = YES;
-                             }];
-  base::test::ios::WaitUntilCondition(^bool() {
-    return completion_handler_was_called;
-  });
-  ASSERT_TRUE(completion_handler_was_called);
-}
-
-}  // namespace
diff --git a/ios/chrome/browser/ui/main/main_coordinator.mm b/ios/chrome/browser/ui/main/main_coordinator.mm
index d5c21461..4aa690c 100644
--- a/ios/chrome/browser/ui/main/main_coordinator.mm
+++ b/ios/chrome/browser/ui/main/main_coordinator.mm
@@ -5,8 +5,6 @@
 #import "ios/chrome/browser/ui/main/main_coordinator.h"
 
 #include "base/logging.h"
-#import "ios/chrome/browser/ui/main/main_containing_view_controller.h"
-#include "ios/chrome/browser/ui/main/main_feature_flags.h"
 #import "ios/chrome/browser/ui/main/main_presenting_view_controller.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -36,13 +34,8 @@
 #pragma mark - ChromeCoordinator implementation.
 
 - (void)start {
-  UIViewController<ViewControllerSwapping>* mainViewController = nil;
-  if (TabSwitcherPresentsBVCEnabled()) {
-    mainViewController = [[MainPresentingViewController alloc] init];
-  } else {
-    mainViewController = [[MainContainingViewController alloc] init];
-  }
-  CHECK(mainViewController);
+  UIViewController<ViewControllerSwapping>* mainViewController =
+      [[MainPresentingViewController alloc] init];
   _mainViewController = mainViewController;
   self.window.rootViewController = self.mainViewController;
 }
diff --git a/ios/chrome/browser/ui/main/main_feature_flags.cc b/ios/chrome/browser/ui/main/main_feature_flags.cc
deleted file mode 100644
index 27b8826..0000000
--- a/ios/chrome/browser/ui/main/main_feature_flags.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ios/chrome/browser/ui/main/main_feature_flags.h"
-
-const base::Feature kTabSwitcherPresentsBVC{"TabSwitcherPresentsBVC",
-                                            base::FEATURE_ENABLED_BY_DEFAULT};
-
-bool TabSwitcherPresentsBVCEnabled() {
-  return base::FeatureList::IsEnabled(kTabSwitcherPresentsBVC);
-}
diff --git a/ios/chrome/browser/ui/main/main_feature_flags.h b/ios/chrome/browser/ui/main/main_feature_flags.h
deleted file mode 100644
index 17462b0..0000000
--- a/ios/chrome/browser/ui/main/main_feature_flags.h
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef IOS_CHROME_BROWSER_UI_MAIN_MAIN_FEATURE_FLAGS_H_
-#define IOS_CHROME_BROWSER_UI_MAIN_MAIN_FEATURE_FLAGS_H_
-
-#include "base/feature_list.h"
-
-extern const base::Feature kTabSwitcherPresentsBVC;
-
-// Returns whether the tab switcher will present the BVC..
-bool TabSwitcherPresentsBVCEnabled();
-
-#endif  // IOS_CHROME_BROWSER_UI_MAIN_MAIN_FEATURE_FLAGS_H_
diff --git a/ios/chrome/browser/ui/open_in_controller.h b/ios/chrome/browser/ui/open_in_controller.h
index 50c8517..fd89aac 100644
--- a/ios/chrome/browser/ui/open_in_controller.h
+++ b/ios/chrome/browser/ui/open_in_controller.h
@@ -13,8 +13,8 @@
 #import "ios/chrome/browser/ui/open_in_toolbar.h"
 #include "url/gurl.h"
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
 }
 
 @class CRWWebController;
@@ -23,8 +23,9 @@
 @interface OpenInController : NSObject<UIGestureRecognizerDelegate,
                                        UIDocumentInteractionControllerDelegate>
 // Designated initializer.
-- (id)initWithRequestContext:(net::URLRequestContextGetter*)requestContext
-               webController:(CRWWebController*)webController;
+- (id)initWithURLLoaderFactory:
+          (scoped_refptr<network::SharedURLLoaderFactory>)urlLoaderFactory
+                 webController:(CRWWebController*)webController;
 
 // Base view on which the Open In toolbar will be presented.
 @property(nonatomic, weak) UIView* baseView;
diff --git a/ios/chrome/browser/ui/open_in_controller.mm b/ios/chrome/browser/ui/open_in_controller.mm
index db37595..6ecc569 100644
--- a/ios/chrome/browser/ui/open_in_controller.mm
+++ b/ios/chrome/browser/ui/open_in_controller.mm
@@ -25,9 +25,8 @@
 #include "ios/web/public/web_thread.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #include "net/base/load_flags.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 #include "ui/base/l10n/l10n_util_mac.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
 #include "url/gurl.h"
@@ -41,8 +40,6 @@
 // other applications.
 static NSString* const kDocumentsTempPath = @"OpenIn";
 
-static const int kHTTPResponseCodeSucceeded = 200;
-
 // Duration of the show/hide animation for the |openInToolbar_|.
 const NSTimeInterval kOpenInToolbarAnimationDuration = 0.2;
 
@@ -77,8 +74,8 @@
 // updated. Used to know in which direction the scroll view is scrolling.
 @property(nonatomic, assign) CGFloat previousScrollViewOffset;
 
-// URLFetcher delegate method called when |fetcher_| completes a request.
-- (void)urlFetchDidComplete:(const net::URLFetcher*)source;
+// SimpleURLLoader completion callback, when |urlLoader_| completes a request.
+- (void)urlLoadDidComplete:(const base::FilePath&)file_path;
 // Ensures the destination directory is created and any contained obsolete files
 // are deleted. Returns YES if the directory is created successfully.
 + (BOOL)createDestinationDirectoryAndRemoveObsoleteFiles;
@@ -120,16 +117,10 @@
 
 // Bridge to deliver method calls from C++ to the |OpenInController| class.
 class OpenInControllerBridge
-    : public net::URLFetcherDelegate,
-      public base::RefCountedThreadSafe<OpenInControllerBridge> {
+    : public base::RefCountedThreadSafe<OpenInControllerBridge> {
  public:
   explicit OpenInControllerBridge(OpenInController* owner) : owner_(owner) {}
 
-  void OnURLFetchComplete(const net::URLFetcher* source) override {
-    DCHECK(owner_);
-    [owner_ urlFetchDidComplete:source];
-  }
-
   BOOL CreateDestinationDirectoryAndRemoveObsoleteFiles(void) {
     return [OpenInController createDestinationDirectoryAndRemoveObsoleteFiles];
   }
@@ -157,7 +148,7 @@
 
  protected:
   friend base::RefCountedThreadSafe<OpenInControllerBridge>;
-  ~OpenInControllerBridge() override {}
+  virtual ~OpenInControllerBridge() {}
 
  private:
   __weak OpenInController* owner_;
@@ -185,15 +176,15 @@
   // Suggested filename for the document.
   NSString* suggestedFilename_;
 
-  // Fetcher used to redownload the document and save it in the sandbox.
-  std::unique_ptr<net::URLFetcher> fetcher_;
+  // Loader used to redownload the document and save it in the sandbox.
+  std::unique_ptr<network::SimpleURLLoader> urlLoader_;
 
   // CRWWebController used to check if the tap is not on a link and the
   // |openInToolbar_| should be displayed.
   CRWWebController* webController_;
 
-  // URLRequestContextGetter needed for the URLFetcher.
-  scoped_refptr<net::URLRequestContextGetter> requestContext_;
+  // URLLoaderFactory instance needed for URLLoader.
+  scoped_refptr<network::SharedURLLoaderFactory> urlLoaderFactory_;
 
   // Spinner view displayed while the file is downloading.
   UIView* overlayedView_;
@@ -217,11 +208,12 @@
 @synthesize baseView = _baseView;
 @synthesize previousScrollViewOffset = _previousScrollViewOffset;
 
-- (id)initWithRequestContext:(net::URLRequestContextGetter*)requestContext
-               webController:(CRWWebController*)webController {
+- (id)initWithURLLoaderFactory:
+          (scoped_refptr<network::SharedURLLoaderFactory>)urlLoaderFactory
+                 webController:(CRWWebController*)webController {
   self = [super init];
   if (self) {
-    requestContext_ = requestContext;
+    urlLoaderFactory_ = std::move(urlLoaderFactory);
     webController_ = webController;
     tapRecognizer_ = [[UITapGestureRecognizer alloc]
         initWithTarget:self
@@ -261,7 +253,7 @@
   [documentController_ setDelegate:nil];
   documentURL_ = GURL();
   suggestedFilename_ = nil;
-  fetcher_.reset();
+  urlLoader_.reset();
 }
 
 - (void)detachFromWebController {
@@ -370,13 +362,17 @@
     bridge_ = new OpenInControllerBridge(self);
 
   // Download the document and save it at |filePath|.
-  fetcher_ = net::URLFetcher::Create(0, documentURL_, net::URLFetcher::GET,
-                                     bridge_.get());
-  fetcher_->SetRequestContext(requestContext_.get());
-  fetcher_->SetLoadFlags(net::LOAD_SKIP_CACHE_VALIDATION);
-  fetcher_->SaveResponseToFileAtPath(
-      base::FilePath(base::SysNSStringToUTF8(filePath)), sequencedTaskRunner_);
-  fetcher_->Start();
+  auto resourceRequest = std::make_unique<network::ResourceRequest>();
+  resourceRequest->url = documentURL_;
+  resourceRequest->load_flags = net::LOAD_SKIP_CACHE_VALIDATION;
+
+  urlLoader_ = network::SimpleURLLoader::Create(std::move(resourceRequest),
+                                                NO_TRAFFIC_ANNOTATION_YET);
+  urlLoader_->DownloadToFile(urlLoaderFactory_.get(),
+                             base::BindOnce(^(base::FilePath filePath) {
+                               [self urlLoadDidComplete:filePath];
+                             }),
+                             base::FilePath(base::SysNSStringToUTF8(filePath)));
 }
 
 - (void)handleTapOnOverlayedView:(UIGestureRecognizer*)gestureRecognizer {
@@ -424,9 +420,9 @@
   if (!webController_)
     return;
 
-  if (requestContext_.get()) {
-    // |requestContext_| is nil only if this is called from a unit test, in
-    // which case the |documentController_| was set already.
+  if (!documentController_) {
+    // If this is called from a unit test, |documentController_| was set
+    // already.
     documentController_ =
         [UIDocumentInteractionController interactionControllerWithURL:fileURL];
   }
@@ -439,17 +435,15 @@
       [documentController_ presentOpenInMenuFromRect:anchorLocation_
                                               inView:[webController_ view]
                                             animated:YES];
-  if (requestContext_.get()) {
-    [self removeOverlayedView];
-    if (!success) {
-      if (IsIPadIdiom())
-        [self hideOpenInToolbar];
-      NSString* errorMessage =
-          l10n_util::GetNSStringWithFixup(IDS_IOS_OPEN_IN_NO_APPS_REGISTERED);
-      [self showErrorWithMessage:errorMessage];
-    } else {
-      isOpenInMenuDisplayed_ = YES;
-    }
+  [self removeOverlayedView];
+  if (!success) {
+    if (IsIPadIdiom())
+      [self hideOpenInToolbar];
+    NSString* errorMessage =
+        l10n_util::GetNSStringWithFixup(IDS_IOS_OPEN_IN_NO_APPS_REGISTERED);
+    [self showErrorWithMessage:errorMessage];
+  } else {
+    isOpenInMenuDisplayed_ = YES;
   }
 }
 
@@ -589,16 +583,8 @@
   return YES;
 }
 
-#pragma mark -
-#pragma mark URLFetcher delegate method
-
-- (void)urlFetchDidComplete:(const net::URLFetcher*)fetcher {
-  DCHECK(fetcher);
-  if (requestContext_.get())
-    DCHECK_CURRENTLY_ON(web::WebThread::UI);
-  base::FilePath filePath;
-  if (fetcher->GetResponseCode() == kHTTPResponseCodeSucceeded &&
-      fetcher->GetResponseAsFilePath(true, &filePath)) {
+- (void)urlLoadDidComplete:(const base::FilePath&)filePath {
+  if (!filePath.empty()) {
     NSURL* fileURL =
         [NSURL fileURLWithPath:base::SysUTF8ToNSString(filePath.value())];
     if (downloadCanceled_) {
diff --git a/ios/chrome/browser/ui/open_in_controller_unittest.mm b/ios/chrome/browser/ui/open_in_controller_unittest.mm
index 77abe37..493acb7 100644
--- a/ios/chrome/browser/ui/open_in_controller_unittest.mm
+++ b/ios/chrome/browser/ui/open_in_controller_unittest.mm
@@ -6,8 +6,9 @@
 
 #include <memory>
 
-#include "base/message_loop/message_loop.h"
+#include "base/files/file_util.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/ui/open_in_controller.h"
 #import "ios/chrome/browser/ui/open_in_controller_testing.h"
@@ -15,6 +16,8 @@
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher_delegate.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/platform_test.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
@@ -27,37 +30,48 @@
 
 class OpenInControllerTest : public PlatformTest {
  public:
-  OpenInControllerTest() {
-    io_thread_.reset(
-        new web::TestWebThread(web::WebThread::IO, &message_loop_));
-  }
+  OpenInControllerTest()
+      : test_shared_url_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)) {}
 
   void TearDown() override { PlatformTest::TearDown(); }
 
   void SetUp() override {
     PlatformTest::SetUp();
+
+    // Set up the directory it downloads the file to.
+    // Note that the value of kDocumentsTempPath must match the one in
+    // open_in_controller.mm
+    {
+      NSString* const kDocumentsTempPath = @"OpenIn";
+      NSString* tempDirPath = [NSTemporaryDirectory()
+          stringByAppendingPathComponent:kDocumentsTempPath];
+      base::FilePath directory(base::SysNSStringToUTF8(tempDirPath));
+      EXPECT_TRUE(base::CreateDirectory(directory));
+    }
+
     GURL documentURL = GURL("http://www.test.com/doc.pdf");
     parent_view_ = [[UIView alloc] init];
     id webController = [OCMockObject niceMockForClass:[CRWWebController class]];
-    open_in_controller_ =
-        [[OpenInController alloc] initWithRequestContext:nil
-                                           webController:webController];
+    open_in_controller_ = [[OpenInController alloc]
+        initWithURLLoaderFactory:test_shared_url_loader_factory_
+                   webController:webController];
     [open_in_controller_ enableWithDocumentURL:documentURL
                              suggestedFilename:@"doc.pdf"];
   }
-  // |TestURLFetcher| requires a |MessageLoop|.
-  base::MessageLoopForUI message_loop_;
-  // Add |io_thread_| to release |URLRequestContextGetter| in
-  // |URLFetcher::Core|.
-  std::unique_ptr<web::TestWebThread> io_thread_;
-  // Creates a |TestURLFetcherFactory|, which automatically sets itself as
-  // |URLFetcher|'s factory.
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory>
+      test_shared_url_loader_factory_;
+
   net::TestURLFetcherFactory factory_;
   OpenInController* open_in_controller_;
   UIView* parent_view_;
 };
 
-TEST_F(OpenInControllerTest, DISABLED_TestDisplayOpenInMenu) {
+TEST_F(OpenInControllerTest, TestDisplayOpenInMenu) {
   id documentController =
       [OCMockObject niceMockForClass:[UIDocumentInteractionController class]];
   [open_in_controller_ setDocumentInteractionController:documentController];
@@ -67,19 +81,20 @@
                          inView:OCMOCK_ANY
                        animated:YES];
 
-  net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
-  DCHECK(fetcher);
-  DCHECK(fetcher->delegate());
-  fetcher->set_response_code(200);
+  auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
+  DCHECK(pending_request);
   // Set the response for the set URLFetcher to be a blank PDF.
   NSMutableData* pdfData = [NSMutableData data];
   UIGraphicsBeginPDFContextToData(pdfData, CGRectMake(0, 0, 100, 100), @{});
   UIGraphicsBeginPDFPage();
   UIGraphicsEndPDFContext();
   unsigned char* array = (unsigned char*)[pdfData bytes];
-  fetcher->SetResponseString(std::string((char*)array, sizeof(pdfData)));
-  fetcher->SetResponseFilePath(base::FilePath("path/to/file.pdf"));
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+  test_url_loader_factory_.SimulateResponseForPendingRequest(
+      pending_request->request.url.spec(),
+      std::string((char*)array, sizeof(pdfData)));
+  scoped_task_environment_.RunUntilIdle();
+
   EXPECT_OCMOCK_VERIFY(documentController);
 }
 
diff --git a/ios/chrome/browser/ui/settings/cells/BUILD.gn b/ios/chrome/browser/ui/settings/cells/BUILD.gn
index 28da409a..4fbac99 100644
--- a/ios/chrome/browser/ui/settings/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/cells/BUILD.gn
@@ -30,6 +30,8 @@
     "settings_collapsible_item.mm",
     "settings_detail_item.h",
     "settings_detail_item.mm",
+    "settings_image_detail_text_item.h",
+    "settings_image_detail_text_item.mm",
     "settings_search_item.h",
     "settings_search_item.mm",
     "settings_switch_item.h",
diff --git a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h
new file mode 100644
index 0000000..0f584412
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.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 IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
+#define IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
+
+#import <Foundation/Foundation.h>
+
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
+#import "ios/third_party/material_components_ios/src/components/CollectionCells/src/MaterialCollectionCells.h"
+
+// SettingsImageDetailTextItem is an item that displays an image, a title and
+// a detail text (optional). This item uses multi-lines text field. It also
+// contains acommand id.
+// This class is intended to be used with Google services settings view.
+@interface SettingsImageDetailTextItem : CollectionViewItem
+
+// The image to display.
+@property(nonatomic, strong) UIImage* image;
+
+// The title text to display.
+@property(nonatomic, copy) NSString* text;
+
+// The detail text to display.
+@property(nonatomic, copy) NSString* detailText;
+
+@end
+
+// Cell representation for SettingsImageDetailTextItem.
+//  +--------------------------------------------------+
+//  |  +-------+                                       |
+//  |  | image |   Multiline title                     |
+//  |  |       |   Optional multiline detail text      |
+//  |  +-------+                                       |
+//  +--------------------------------------------------+
+@interface SettingsImageDetailTextCell : MDCCollectionViewCell
+
+// Cell image.
+@property(nonatomic, readonly, strong) UIImageView* imageView;
+
+// Cell title.
+@property(nonatomic, readonly, strong) UILabel* textLabel;
+
+// Cell subtitle.
+@property(nonatomic, readonly, strong) UILabel* detailTextLabel;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_SETTINGS_CELLS_SETTINGS_IMAGE_DETAIL_TEXT_ITEM_H_
diff --git a/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm
new file mode 100644
index 0000000..f8b64fc
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.mm
@@ -0,0 +1,161 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
+
+#include "ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+
+// Padding used on the leading and trailing edges of the cell.
+const CGFloat kHorizontalPadding = 16;
+
+// Padding used on the top and bottom edges of the cell.
+const CGFloat kVerticalPadding = 16;
+
+// Image height and width.
+const CGFloat kImageSize = 40;
+
+// Padding used between the image and text.
+const CGFloat kHorizontalImagePadding = 10;
+
+}  // namespace
+
+@interface SettingsImageDetailTextCell ()
+
+// Container view which contains |self.textLabel| and |self.detailTextLabel|.
+@property(nonatomic, strong) UIStackView* textStackView;
+
+@end
+
+#pragma mark - SettingsImageDetailTextItem
+
+@implementation SettingsImageDetailTextItem
+
+@synthesize image = _image;
+@synthesize text = _text;
+@synthesize detailText = _detailText;
+
+- (instancetype)initWithType:(NSInteger)type {
+  self = [super initWithType:type];
+  if (self) {
+    self.cellClass = [SettingsImageDetailTextCell class];
+  }
+  return self;
+}
+
+- (void)configureCell:(SettingsImageDetailTextCell*)cell {
+  [super configureCell:cell];
+  cell.isAccessibilityElement = YES;
+  cell.textLabel.text = self.text;
+  cell.detailTextLabel.text = self.detailText;
+  cell.imageView.image = self.image;
+}
+
+@end
+
+#pragma mark - SettingsImageDetailTextCell
+
+@implementation SettingsImageDetailTextCell
+
+@synthesize imageView = _imageView;
+@synthesize textLabel = _textLabel;
+@synthesize detailTextLabel = _detailTextLabel;
+@synthesize textStackView = _textStackView;
+
+- (instancetype)initWithFrame:(CGRect)frame {
+  self = [super initWithFrame:frame];
+  if (self) {
+    UIView* contentView = self.contentView;
+
+    _imageView = [[UIImageView alloc] init];
+    _imageView.translatesAutoresizingMaskIntoConstraints = NO;
+    [contentView addSubview:_imageView];
+
+    _textLabel = [[UILabel alloc] init];
+    _textLabel.numberOfLines = 0;
+    _textLabel.font = [UIFont systemFontOfSize:kUIKitMainFontSize];
+    _textLabel.textColor = UIColorFromRGB(kUIKitMainTextColor);
+
+    _detailTextLabel = [[UILabel alloc] init];
+    _detailTextLabel.numberOfLines = 0;
+    _detailTextLabel.font =
+        [UIFont systemFontOfSize:kUIKitMultilineDetailFontSize];
+    _detailTextLabel.textColor = UIColorFromRGB(kUIKitMultilineDetailTextColor);
+
+    _textStackView = [[UIStackView alloc]
+        initWithArrangedSubviews:@[ _textLabel, _detailTextLabel ]];
+    _textStackView.axis = UILayoutConstraintAxisVertical;
+    _textStackView.translatesAutoresizingMaskIntoConstraints = NO;
+    [contentView addSubview:_textStackView];
+
+    [NSLayoutConstraint activateConstraints:@[
+      // Horizontal contraints for |_imageView| and |_textStackView|.
+      [_imageView.heightAnchor constraintEqualToConstant:kImageSize],
+      [_imageView.widthAnchor constraintEqualToConstant:kImageSize],
+      [_imageView.leadingAnchor
+          constraintEqualToAnchor:contentView.leadingAnchor
+                         constant:kHorizontalPadding],
+      [_textStackView.leadingAnchor
+          constraintEqualToAnchor:_imageView.trailingAnchor
+                         constant:kHorizontalImagePadding],
+      [contentView.trailingAnchor
+          constraintEqualToAnchor:_textStackView.trailingAnchor
+                         constant:kHorizontalPadding],
+      // Vertical contraints for |_imageView| and |_textStackView|.
+      [_imageView.centerYAnchor
+          constraintEqualToAnchor:contentView.centerYAnchor],
+      [_imageView.topAnchor
+          constraintGreaterThanOrEqualToAnchor:contentView.topAnchor
+                                      constant:kVerticalPadding],
+      [contentView.bottomAnchor
+          constraintGreaterThanOrEqualToAnchor:_imageView.bottomAnchor
+                                      constant:kVerticalPadding],
+      [_textStackView.centerYAnchor
+          constraintEqualToAnchor:contentView.centerYAnchor],
+      [_textStackView.topAnchor
+          constraintGreaterThanOrEqualToAnchor:contentView.topAnchor
+                                      constant:kVerticalPadding],
+      [contentView.bottomAnchor
+          constraintGreaterThanOrEqualToAnchor:_textStackView.bottomAnchor
+                                      constant:kVerticalPadding],
+    ]];
+  }
+  return self;
+}
+
+// Implement -layoutSubviews as per instructions in documentation for
+// +[MDCCollectionViewCell cr_preferredHeightForWidth:forItem:]."
+- (void)layoutSubviews {
+  [super layoutSubviews];
+  // Adjust the text and detailText label preferredMaxLayoutWidth when the
+  // parent's width changes, for instance on screen rotation.
+  CGFloat prefferedMaxLayoutWidth = CGRectGetWidth(self.contentView.frame) -
+                                    CGRectGetWidth(self.imageView.frame) -
+                                    2 * kHorizontalPadding -
+                                    kHorizontalImagePadding;
+  self.textLabel.preferredMaxLayoutWidth = prefferedMaxLayoutWidth;
+  self.detailTextLabel.preferredMaxLayoutWidth = prefferedMaxLayoutWidth;
+
+  // Re-layout with the new preferred width to allow the label to adjust its
+  // height.
+  [super layoutSubviews];
+}
+
+#pragma mark - UIAccessibility
+
+- (NSString*)accessibilityLabel {
+  if (self.detailTextLabel.text) {
+    return [NSString stringWithFormat:@"%@, %@", self.textLabel.text,
+                                      self.detailTextLabel.text];
+  }
+  return self.textLabel.text;
+}
+
+@end
diff --git a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
index 24e2205c..d8d06fb 100644
--- a/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/material_cell_catalog_view_controller.mm
@@ -39,6 +39,7 @@
 #import "ios/chrome/browser/ui/settings/cells/passphrase_error_item.h"
 #import "ios/chrome/browser/ui/settings/cells/password_details_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_detail_item.h"
+#import "ios/chrome/browser/ui/settings/cells/settings_image_detail_text_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_search_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_text_item.h"
@@ -115,6 +116,7 @@
   ItemTypeSyncEncryptionChecked,
   ItemTypeSyncPassphraseError,
   ItemTypeContentSuggestions,
+  ItemTypeImageDetailTextItem,
 };
 
 // Image fixed horizontal size.
@@ -257,6 +259,25 @@
       @"incididunt ut labore et dolore magna aliqua.";
   [model addItem:multilineDetailItem
       toSectionWithIdentifier:SectionIdentifierMultilineCell];
+  [model addItem:[self settingsImageDetailTextItem]
+      toSectionWithIdentifier:SectionIdentifierMultilineCell];
+  SettingsImageDetailTextItem* settingsImageDetailTextItem =
+      [self settingsImageDetailTextItem];
+  settingsImageDetailTextItem.text = @"Short title";
+  [model addItem:settingsImageDetailTextItem
+      toSectionWithIdentifier:SectionIdentifierMultilineCell];
+  settingsImageDetailTextItem = [self settingsImageDetailTextItem];
+  settingsImageDetailTextItem.detailText = @"Short detail text";
+  [model addItem:settingsImageDetailTextItem
+      toSectionWithIdentifier:SectionIdentifierMultilineCell];
+  settingsImageDetailTextItem = [self settingsImageDetailTextItem];
+  settingsImageDetailTextItem.detailText =
+      @"Text multiline that works nice with a very very very very very long "
+      @"text Text multiline that works nice with a very very very very very "
+      @"long text Text multiline that works nice with a very very very very "
+      @"very long text";
+  [model addItem:settingsImageDetailTextItem
+      toSectionWithIdentifier:SectionIdentifierMultilineCell];
 
   // Switch cells.
   [model addSectionWithIdentifier:SectionIdentifierSwitchCell];
@@ -402,7 +423,7 @@
 
   // Content Suggestions cells.
   [model addSectionWithIdentifier:SectionIdentifierContentSuggestionsCell];
-  [model addItem:[self ContentSuggestionsItem]
+  [model addItem:[self contentSuggestionsItem]
       toSectionWithIdentifier:SectionIdentifierContentSuggestionsCell];
   [model addItem:[self contentSuggestionsFooterItem]
       toSectionWithIdentifier:SectionIdentifierContentSuggestionsCell];
@@ -427,6 +448,7 @@
   CollectionViewItem* item =
       [self.collectionViewModel itemAtIndexPath:indexPath];
   switch (item.type) {
+    case ItemTypeImageDetailTextItem:
     case ItemTypeContentSuggestions:
     case ItemTypeFooter:
     case ItemTypeSwitchDynamicHeight:
@@ -794,7 +816,7 @@
   return footerItem;
 }
 
-- (ContentSuggestionsItem*)ContentSuggestionsItem {
+- (ContentSuggestionsItem*)contentSuggestionsItem {
   ContentSuggestionsItem* articleItem = [[ContentSuggestionsItem alloc]
       initWithType:ItemTypeContentSuggestions
              title:@"This is an incredible article, you should read it!"
@@ -803,6 +825,18 @@
   return articleItem;
 }
 
+- (SettingsImageDetailTextItem*)settingsImageDetailTextItem {
+  SettingsImageDetailTextItem* settingsImageDetailTextItem =
+      [[SettingsImageDetailTextItem alloc]
+          initWithType:ItemTypeImageDetailTextItem];
+  settingsImageDetailTextItem.image =
+      [UIImage imageNamed:@"ios_default_avatar"];
+  settingsImageDetailTextItem.text =
+      @"Text multiline that works nice with a very very very very very long "
+      @"text";
+  return settingsImageDetailTextItem;
+}
+
 - (ContentSuggestionsFooterItem*)contentSuggestionsFooterItem {
   ContentSuggestionsFooterItem* footerItem =
       [[ContentSuggestionsFooterItem alloc]
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.h b/ios/chrome/browser/ui/settings/settings_navigation_controller.h
index d153a84..7b185f76 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.h
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.h
@@ -78,15 +78,6 @@
                              delegate:(id<SettingsNavigationControllerDelegate>)
                                           delegate;
 
-// Creates a new ClearBrowsingDataCollectionViewController and the chrome around
-// it.
-// |browserState| is used to personalize some settings aspects and should not be
-// nil. |delegate| may be nil.
-+ (SettingsNavigationController*)
-newClearBrowsingDataController:(ios::ChromeBrowserState*)browserState
-                      delegate:
-                          (id<SettingsNavigationControllerDelegate>)delegate;
-
 // Creates a new SavePasswordsCollectionViewController and the chrome around it.
 // |browserState| is used to personalize some settings aspects and should not be
 // nil. |delegate| may be nil.
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
index d5660f2..5551c51 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -17,7 +17,6 @@
 #import "ios/chrome/browser/ui/material_components/utils.h"
 #import "ios/chrome/browser/ui/settings/accounts_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/autofill_profile_collection_view_controller.h"
-#import "ios/chrome/browser/ui/settings/clear_browsing_data_collection_view_controller.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_coordinator.h"
 #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller.h"
 #import "ios/chrome/browser/ui/settings/import_data_collection_view_controller.h"
@@ -182,22 +181,6 @@
 }
 
 + (SettingsNavigationController*)
-newClearBrowsingDataController:(ios::ChromeBrowserState*)browserState
-                      delegate:
-                          (id<SettingsNavigationControllerDelegate>)delegate {
-  ClearBrowsingDataCollectionViewController* controller =
-      [[ClearBrowsingDataCollectionViewController alloc]
-          initWithBrowserState:browserState];
-  controller.dispatcher = [delegate dispatcherForSettings];
-  SettingsNavigationController* nc = [[SettingsNavigationController alloc]
-      initWithRootViewController:controller
-                    browserState:browserState
-                        delegate:delegate];
-  [controller navigationItem].rightBarButtonItem = [nc doneButton];
-  return nc;
-}
-
-+ (SettingsNavigationController*)
 newSyncEncryptionPassphraseController:(ios::ChromeBrowserState*)browserState
                              delegate:(id<SettingsNavigationControllerDelegate>)
                                           delegate {
diff --git a/ios/chrome/browser/web/forms_egtest.mm b/ios/chrome/browser/web/forms_egtest.mm
index ea3e1a3..1c992cf 100644
--- a/ios/chrome/browser/web/forms_egtest.mm
+++ b/ios/chrome/browser/web/forms_egtest.mm
@@ -250,6 +250,15 @@
   // Go to a new page and go back and check that the data is reposted.
   [ChromeEarlGrey loadURL:GetGenericUrl()];
   [ChromeEarlGrey goBack];
+
+  // WKBasedNavigationManager doesn't triggere repost on |goForward| due to
+  // WKWebView's back-forward cache. Force reload to trigger repost. Not using
+  // [ChromeEarlGrey reload] because WKBasedNavigationManager presents repost
+  // confirmation dialog before loading stops.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    [chrome_test_util::BrowserCommandDispatcherForMainBVC() reload];
+  }
+
   [self confirmResendWarning];
   [ChromeEarlGrey waitForWebViewContainingText:kDestinationText];
   [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())]
@@ -271,6 +280,15 @@
 
   [ChromeEarlGrey goBack];
   [ChromeEarlGrey goForward];
+
+  // WKBasedNavigationManager doesn't triggere repost on |goForward| due to
+  // WKWebView's back-forward cache. Force reload to trigger repost. Not using
+  // [ChromeEarlGrey reload] because WKBasedNavigationManager presents repost
+  // confirmation dialog before loading stops.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    [chrome_test_util::BrowserCommandDispatcherForMainBVC() reload];
+  }
+
   [self confirmResendWarning];
   [ChromeEarlGrey waitForWebViewContainingText:kDestinationText];
   [[EarlGrey selectElementWithMatcher:OmniboxText(destinationURL.GetContent())]
@@ -325,16 +343,38 @@
   [ChromeEarlGrey goBack];
   [ChromeEarlGrey goForward];
 
+  // WKBasedNavigationManager doesn't triggere repost on |goForward| due to
+  // WKWebView's back-forward cache. Force reload to trigger repost. Not using
+  // [ChromeEarlGrey reload] because WKBasedNavigationManager presents repost
+  // confirmation dialog before loading stops.
+  if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    [chrome_test_util::BrowserCommandDispatcherForMainBVC() reload];
+  }
+
   [[EarlGrey selectElementWithMatcher:ElementToDismissAlert(@"Cancel")]
       performAction:grey_tap()];
   [ChromeEarlGrey waitForPageToFinishLoading];
 
-  // Verify that navigation was cancelled, and forward navigation is possible.
-  [ChromeEarlGrey waitForWebViewContainingText:kSubmitButtonLabel];
-  [[EarlGrey selectElementWithMatcher:OmniboxText(GetFormUrl().GetContent())]
-      assertWithMatcher:grey_notNil()];
-  [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()]
-      assertWithMatcher:grey_interactable()];
+  // Expected behavior is different between the two navigation manager
+  // implementations.
+  if (!web::GetWebClient()->IsSlimNavigationManagerEnabled()) {
+    // LegacyNavigationManager displays repost on |goBack|. So after cancelling,
+    // web view should show form URL.
+    [ChromeEarlGrey waitForWebViewContainingText:kSubmitButtonLabel];
+    [[EarlGrey selectElementWithMatcher:OmniboxText(GetFormUrl().GetContent())]
+        assertWithMatcher:grey_notNil()];
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::ForwardButton()]
+        assertWithMatcher:grey_interactable()];
+  } else {
+    // WKBasedNavigationManager displays repost on |reload|. So after
+    // cancelling, web view should show |destinationURL|.
+    [ChromeEarlGrey waitForWebViewContainingText:kDestinationText];
+    [[EarlGrey
+        selectElementWithMatcher:OmniboxText(destinationURL.GetContent())]
+        assertWithMatcher:grey_notNil()];
+    [[EarlGrey selectElementWithMatcher:chrome_test_util::BackButton()]
+        assertWithMatcher:grey_interactable()];
+  }
 }
 
 // A new navigation dismisses the repost dialog.
diff --git a/ios/chrome/test/data/favicon/test_favicon.png b/ios/chrome/test/data/favicon/test_favicon.png
deleted file mode 100644
index e9100dae..0000000
--- a/ios/chrome/test/data/favicon/test_favicon.png
+++ /dev/null
Binary files differ
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn
index 67f6ded..ee525a4 100644
--- a/ios/third_party/material_components_ios/BUILD.gn
+++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -8,7 +8,9 @@
   visibility = [ ":material_components_ios" ]
   include_dirs = [
     "src/components/ActivityIndicator/src",
+    "src/components/Buttons/src/ShapeThemer",
     "src/components/AppBar/src",
+    "src/components/private/ShapeLibrary/src",
     "src/components/ButtonBar/src",
     "src/components/Buttons/src",
     "src/components/CollectionCells/src",
@@ -30,6 +32,7 @@
     "src/components/private/Shapes/src/",
     "src/components/private/UIMetrics/src",
     "src/components/schemes/Color/src",
+    "src/components/schemes/Shape/src",
     "src/components/schemes/Typography/src",
   ]
 }
@@ -120,6 +123,11 @@
     "src/components/Buttons/src/MDCRaisedButton.h",
     "src/components/Buttons/src/MDCRaisedButton.m",
     "src/components/Buttons/src/MaterialButtons.h",
+    "src/components/Buttons/src/ShapeThemer/MDCButtonShapeThemer.h",
+    "src/components/Buttons/src/ShapeThemer/MDCButtonShapeThemer.m",
+    "src/components/Buttons/src/ShapeThemer/MDCFloatingButtonShapeThemer.h",
+    "src/components/Buttons/src/ShapeThemer/MDCFloatingButtonShapeThemer.m",
+    "src/components/Buttons/src/ShapeThemer/MaterialButtons+ShapeThemer.h",
     "src/components/Buttons/src/TypographyThemer/MDCButtonTypographyThemer.h",
     "src/components/Buttons/src/TypographyThemer/MDCButtonTypographyThemer.m",
     "src/components/Buttons/src/private/MDCButton+Subclassing.h",
@@ -180,6 +188,8 @@
     "src/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.h",
     "src/components/FlexibleHeader/src/MDCFlexibleHeaderViewController.m",
     "src/components/FlexibleHeader/src/MaterialFlexibleHeader.h",
+    "src/components/FlexibleHeader/src/private/MDCFlexibleHeaderTopSafeArea.h",
+    "src/components/FlexibleHeader/src/private/MDCFlexibleHeaderTopSafeArea.m",
     "src/components/FlexibleHeader/src/private/MDCStatusBarShifter.h",
     "src/components/FlexibleHeader/src/private/MDCStatusBarShifter.m",
     "src/components/HeaderStackView/src/MDCHeaderStackView.h",
@@ -288,6 +298,14 @@
     "src/components/private/Overlay/src/private/MDCOverlayObserverTransition.m",
     "src/components/private/Overlay/src/private/MDCOverlayUtilities.h",
     "src/components/private/Overlay/src/private/MDCOverlayUtilities.m",
+    "src/components/private/Shapes/src/MDCCornerTreatment.h",
+    "src/components/private/Shapes/src/MDCCornerTreatment.m",
+    "src/components/private/Shapes/src/MDCEdgeTreatment.h",
+    "src/components/private/Shapes/src/MDCEdgeTreatment.m",
+    "src/components/private/Shapes/src/MDCPathGenerator.h",
+    "src/components/private/Shapes/src/MDCPathGenerator.m",
+    "src/components/private/Shapes/src/MDCRectangleShapeGenerator.h",
+    "src/components/private/Shapes/src/MDCRectangleShapeGenerator.m",
     "src/components/private/Shapes/src/MDCShapedShadowLayer.h",
     "src/components/private/Shapes/src/MDCShapedShadowLayer.m",
     "src/components/private/Shapes/src/MDCShapedView.h",
@@ -312,6 +330,10 @@
     "src/components/schemes/Color/src/MDCSemanticColorScheme.h",
     "src/components/schemes/Color/src/MDCSemanticColorScheme.m",
     "src/components/schemes/Color/src/MaterialColorScheme.h",
+    "src/components/schemes/Shape/src/MDCShapeCategory.h",
+    "src/components/schemes/Shape/src/MDCShapeCategory.m",
+    "src/components/schemes/Shape/src/MDCShapeScheme.h",
+    "src/components/schemes/Shape/src/MDCShapeScheme.m",
     "src/components/schemes/Typography/src/MDCLegacyFontScheme.h",
     "src/components/schemes/Typography/src/MDCLegacyFontScheme.m",
     "src/components/schemes/Typography/src/MDCTypographyScheme.h",
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 6446d189..e344f04 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -4358,6 +4358,7 @@
               decisionHandler(WKNavigationActionPolicyCancel);
               if (action.targetFrame.mainFrame) {
                 [_pendingNavigationInfo setCancelled:YES];
+                _webStateImpl->SetIsLoading(false);
               }
             }
           }));
@@ -5549,6 +5550,22 @@
   BOOL sameDocumentNavigation = currentItem->IsCreatedFromPushState() ||
                                 currentItem->IsCreatedFromHashChange();
 
+  if (holder->back_forward_list_item()) {
+    // Check if holder's WKBackForwardListItem still correctly represents
+    // navigation item. With LegacyNavigationManager, replaceState operation
+    // creates a new navigation item, leaving the old item committed. That
+    // old committed item will be associated with WKBackForwardListItem whose
+    // state was replaced. So old item won't have correct WKBackForwardListItem.
+    if (net::GURLWithNSURL(holder->back_forward_list_item().URL) !=
+        currentItem->GetURL()) {
+      // The state was replaced for this item. The item should not be a part of
+      // committed items, but it's too late to remove the item. Cleaup
+      // WKBackForwardListItem and mark item with "state replaced" flag.
+      currentItem->SetHasStateBeenReplaced(true);
+      holder->set_back_forward_list_item(nil);
+    }
+  }
+
   // If the request has POST data and is not a repost form, configure and
   // run the POST request.
   if (POSTData.length && !repostedForm) {
diff --git a/ios/web_view/BUILD.gn b/ios/web_view/BUILD.gn
index e6c22bc..64f0c40 100644
--- a/ios/web_view/BUILD.gn
+++ b/ios/web_view/BUILD.gn
@@ -270,6 +270,7 @@
   "//components/signin/ios/browser:active_state_manager",
   "//components/strings:components_strings_grit",
   "//components/sync",
+  "//components/sync_sessions",
   "//components/translate/core/browser",
   "//components/translate/core/common",
   "//components/translate/ios/browser",
diff --git a/ios/web_view/internal/DEPS b/ios/web_view/internal/DEPS
index 106fa0ae..7636c26 100644
--- a/ios/web_view/internal/DEPS
+++ b/ios/web_view/internal/DEPS
@@ -23,6 +23,7 @@
   "+components/signin/ios",
   "+components/strings/grit",
   "+components/sync",
+  "+components/sync_sessions",
   "+components/translate/core",
   "+components/translate/ios",
   "+components/version_info",
diff --git a/ios/web_view/internal/sync/web_view_sync_client.h b/ios/web_view/internal/sync/web_view_sync_client.h
index 412193e..952f02167 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.h
+++ b/ios/web_view/internal/sync/web_view_sync_client.h
@@ -40,6 +40,7 @@
   bookmarks::BookmarkModel* GetBookmarkModel() override;
   favicon::FaviconService* GetFaviconService() override;
   history::HistoryService* GetHistoryService() override;
+  sync_sessions::SessionSyncService* GetSessionSyncService() override;
   bool HasPasswordStore() override;
   base::RepeatingClosure GetPasswordStateChangedCallback() override;
   syncer::DataTypeController::TypeVector CreateDataTypeControllers(
@@ -48,7 +49,6 @@
   invalidation::InvalidationService* GetInvalidationService() override;
   BookmarkUndoService* GetBookmarkUndoServiceIfExists() override;
   scoped_refptr<syncer::ExtensionsActivity> GetExtensionsActivity() override;
-  sync_sessions::SyncSessionsClient* GetSyncSessionsClient() override;
   base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
       syncer::ModelType type) override;
   base::WeakPtr<syncer::ModelTypeControllerDelegate>
diff --git a/ios/web_view/internal/sync/web_view_sync_client.mm b/ios/web_view/internal/sync/web_view_sync_client.mm
index d661a1a2..2ec1c6b 100644
--- a/ios/web_view/internal/sync/web_view_sync_client.mm
+++ b/ios/web_view/internal/sync/web_view_sync_client.mm
@@ -120,6 +120,10 @@
   return nullptr;
 }
 
+sync_sessions::SessionSyncService* WebViewSyncClient::GetSessionSyncService() {
+  return nullptr;
+}
+
 bool WebViewSyncClient::HasPasswordStore() {
   return true;
 }
@@ -162,10 +166,6 @@
   return nullptr;
 }
 
-sync_sessions::SyncSessionsClient* WebViewSyncClient::GetSyncSessionsClient() {
-  return nullptr;
-}
-
 base::WeakPtr<syncer::SyncableService>
 WebViewSyncClient::GetSyncableServiceForType(syncer::ModelType type) {
   if (!profile_web_data_service_) {
diff --git a/ios/web_view/internal/web_view_browser_state.mm b/ios/web_view/internal/web_view_browser_state.mm
index e444cc1..f8d6be1 100644
--- a/ios/web_view/internal/web_view_browser_state.mm
+++ b/ios/web_view/internal/web_view_browser_state.mm
@@ -24,6 +24,7 @@
 #include "components/signin/ios/browser/active_state_manager.h"
 #include "components/sync/base/pref_names.h"
 #include "components/sync/base/sync_prefs.h"
+#include "components/sync_sessions/session_sync_prefs.h"
 #include "components/translate/core/browser/translate_pref_names.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "ios/web/public/web_task_traits.h"
@@ -177,6 +178,7 @@
 
 #if BUILDFLAG(IOS_WEB_VIEW_ENABLE_SYNC)
   gcm::GCMChannelStatusSyncer::RegisterProfilePrefs(pref_registry);
+  sync_sessions::SessionSyncPrefs::RegisterProfilePrefs(pref_registry);
   syncer::SyncPrefs::RegisterProfilePrefs(pref_registry);
 #endif  // BUILDFLAG(IOS_WEB_VIEW_ENABLE_SYNC)
 
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h
index d1255cb..92741c3f 100644
--- a/media/base/video_frame_metadata.h
+++ b/media/base/video_frame_metadata.h
@@ -130,10 +130,8 @@
     PAGE_SCALE_FACTOR,
     ROOT_SCROLL_OFFSET_X,
     ROOT_SCROLL_OFFSET_Y,
-#if defined(OS_ANDROID)
     TOP_CONTROLS_HEIGHT,
     TOP_CONTROLS_SHOWN_RATIO,
-#endif
 
     NUM_KEYS
   };
diff --git a/media/gpu/windows/d3d11_video_decoder_impl.cc b/media/gpu/windows/d3d11_video_decoder_impl.cc
index 4d9440e4..148a6c66 100644
--- a/media/gpu/windows/d3d11_video_decoder_impl.cc
+++ b/media/gpu/windows/d3d11_video_decoder_impl.cc
@@ -32,8 +32,8 @@
 D3D11VideoDecoderImpl::~D3D11VideoDecoderImpl() {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  if (stub_ && !wait_sequence_id_.is_null())
-    stub_->channel()->scheduler()->DestroySequence(wait_sequence_id_);
+  if (stub_)
+    DestroyStub();
 }
 
 void D3D11VideoDecoderImpl::Initialize(
@@ -55,8 +55,7 @@
 
   return_picture_buffer_cb_ = std::move(return_picture_buffer_cb);
 
-  // TODO(liberato): see GpuVideoFrameFactory.
-  // stub_->AddDestructionObserver(this);
+  stub_->AddDestructionObserver(this);
   wait_sequence_id_ = stub_->channel()->scheduler()->CreateSequence(
       gpu::SchedulingPriority::kNormal);
 
@@ -68,6 +67,9 @@
     const gpu::SyncToken& sync_token) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
+  if (!stub_)
+    return;
+
   stub_->channel()->scheduler()->ScheduleTask(gpu::Scheduler::Task(
       wait_sequence_id_,
       base::BindOnce(&D3D11VideoDecoderImpl::OnSyncTokenReleased, GetWeakPtr(),
@@ -82,6 +84,21 @@
   return_picture_buffer_cb_.Run(std::move(buffer));
 }
 
+void D3D11VideoDecoderImpl::OnWillDestroyStub(bool have_context) {
+  DestroyStub();
+}
+
+void D3D11VideoDecoderImpl::DestroyStub() {
+  DCHECK(stub_);
+  gpu::CommandBufferStub* stub = stub_;
+  stub_ = nullptr;
+
+  stub->RemoveDestructionObserver(this);
+
+  if (!wait_sequence_id_.is_null())
+    stub->channel()->scheduler()->DestroySequence(wait_sequence_id_);
+}
+
 base::WeakPtr<D3D11VideoDecoderImpl> D3D11VideoDecoderImpl::GetWeakPtr() {
   // May be called from any thread.
   return weak_factory_.GetWeakPtr();
diff --git a/media/gpu/windows/d3d11_video_decoder_impl.h b/media/gpu/windows/d3d11_video_decoder_impl.h
index c765a69c..bb71fad7 100644
--- a/media/gpu/windows/d3d11_video_decoder_impl.h
+++ b/media/gpu/windows/d3d11_video_decoder_impl.h
@@ -18,6 +18,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
 #include "gpu/command_buffer/service/sequence_id.h"
+#include "gpu/ipc/service/command_buffer_stub.h"
 #include "media/gpu/media_gpu_export.h"
 
 namespace gpu {
@@ -33,13 +34,14 @@
 // Does the gpu main thread work for D3D11VideoDecoder.  Except as noted, this
 // class lives on the GPU main thread.
 // TODO(liberato): Rename this class as a follow-on to this refactor.
-class MEDIA_GPU_EXPORT D3D11VideoDecoderImpl {
+class MEDIA_GPU_EXPORT D3D11VideoDecoderImpl
+    : public gpu::CommandBufferStub::DestructionObserver {
  public:
   // May be constructed on any thread.
   explicit D3D11VideoDecoderImpl(
       std::unique_ptr<MediaLog> media_log,
       base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb);
-  virtual ~D3D11VideoDecoderImpl();
+  ~D3D11VideoDecoderImpl() override;
 
   using InitCB = base::OnceCallback<void(bool success)>;
 
@@ -64,6 +66,10 @@
  private:
   void OnSyncTokenReleased(scoped_refptr<D3D11PictureBuffer> buffer);
 
+  void OnWillDestroyStub(bool have_context) override;
+
+  void DestroyStub();
+
   std::unique_ptr<MediaLog> media_log_;
 
   base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb_;
diff --git a/pdf/pdf_engine.h b/pdf/pdf_engine.h
index 511118e..13711060 100644
--- a/pdf/pdf_engine.h
+++ b/pdf/pdf_engine.h
@@ -53,10 +53,6 @@
 
 namespace chrome_pdf {
 
-// Zero Width Whitespace character that requires special handling in multiple
-// locations.
-constexpr base::char16 kZeroWidthSpace = 0x200B;
-
 // Do one time initialization of the SDK.
 bool InitializeSDK();
 // Tells the SDK that we're shutting down.
diff --git a/pdf/pdfium/findtext_unittest.cc b/pdf/pdfium/findtext_unittest.cc
index c077b74..068c62a 100644
--- a/pdf/pdfium/findtext_unittest.cc
+++ b/pdf/pdfium/findtext_unittest.cc
@@ -20,13 +20,14 @@
 
 class TestDocumentLoader : public DocumentLoader {
  public:
-  explicit TestDocumentLoader(Client* client) : client_(client) {
+  TestDocumentLoader(Client* client, const base::FilePath::StringType& pdf_name)
+      : client_(client) {
     base::FilePath pdf_path;
     CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &pdf_path));
     pdf_path = pdf_path.Append(FILE_PATH_LITERAL("pdf"))
                    .Append(FILE_PATH_LITERAL("test"))
                    .Append(FILE_PATH_LITERAL("data"))
-                   .Append(FILE_PATH_LITERAL("hello_world2.pdf"));
+                   .Append(pdf_name);
     CHECK(base::ReadFileToString(pdf_path, &pdf_data_));
   }
   ~TestDocumentLoader() override = default;
@@ -66,9 +67,11 @@
   std::string pdf_data_;
 };
 
+const base::FilePath::CharType* g_test_pdf_name;
+
 std::unique_ptr<DocumentLoader> CreateTestDocumentLoader(
     DocumentLoader::Client* client) {
-  return std::make_unique<TestDocumentLoader>(client);
+  return std::make_unique<TestDocumentLoader>(client, g_test_pdf_name);
 }
 
 class TestClient : public PDFEngine::Client {
@@ -137,11 +140,11 @@
  protected:
   void SetUp() override {
     InitializePDFium();
-    PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(
-        &CreateTestDocumentLoader);
   }
+
   void TearDown() override {
     PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(nullptr);
+    g_test_pdf_name = nullptr;
     FPDF_DestroyLibrary();
   }
 
@@ -154,10 +157,18 @@
     FPDF_InitLibraryWithConfig(&config);
   }
 
+  void SetDocumentForTest(const base::FilePath::CharType* test_pdf_name) {
+    g_test_pdf_name = test_pdf_name;
+    PDFiumEngine::SetCreateDocumentLoaderFunctionForTesting(
+        &CreateTestDocumentLoader);
+  }
+
+ private:
   DISALLOW_COPY_AND_ASSIGN(FindTextTest);
 };
 
 TEST_F(FindTextTest, FindText) {
+  SetDocumentForTest(FILE_PATH_LITERAL("hello_world2.pdf"));
   pp::URLLoader dummy_loader;
   TestClient client;
   PDFiumEngine engine(&client, true);
@@ -177,4 +188,24 @@
   engine.StartFind("o", /*case_sensitive=*/true);
 }
 
+TEST_F(FindTextTest, FindHyphenatedText) {
+  SetDocumentForTest(FILE_PATH_LITERAL("spanner.pdf"));
+  pp::URLLoader dummy_loader;
+  TestClient client;
+  PDFiumEngine engine(&client, true);
+  ASSERT_TRUE(engine.New("https://chromium.org/dummy.pdf", ""));
+  ASSERT_TRUE(engine.HandleDocumentLoad(dummy_loader));
+
+  {
+    InSequence sequence;
+
+    EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(1, false));
+    EXPECT_CALL(client, NotifySelectedFindResultChanged(0));
+    for (int i = 1; i < 6; ++i)
+      EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(i + 1, false));
+    EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(6, true));
+  }
+
+  engine.StartFind("application", /*case_sensitive=*/true);
+}
 }  // namespace chrome_pdf
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 25eb931f..e5d03c9 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -1918,28 +1918,65 @@
                        character_to_start_searching_from, text_length, data);
   api_string_adapter.Close(written);
 
+  base::string16 stripped_page_text;
+  stripped_page_text.reserve(page_text.size());
+  // Values in |stripped_indices| are in the stripped text index space and
+  // indicate a character was removed from the page text before the given
+  // index. If multiple characters are removed in a row then there will be
+  // multiple entries with the same value.
+  std::vector<size_t> stripped_indices;
+  for (size_t i = 0; i < page_text.size(); i++) {
+    base::char16 c = page_text[i];
+    if (IsIgnorableCharacter(c))
+      stripped_indices.push_back(stripped_page_text.size());
+    else
+      stripped_page_text.push_back(c);
+  }
+
   std::vector<PDFEngine::Client::SearchStringResult> results =
-      client_->SearchString(page_text.c_str(), term.c_str(), case_sensitive);
+      client_->SearchString(stripped_page_text.c_str(), term.c_str(),
+                            case_sensitive);
   for (const auto& result : results) {
+    // Need to convert from stripped page text start to page text start, by
+    // incrementing for all the characters stripped before it in the string.
+    auto stripped_indices_begin = std::upper_bound(
+        stripped_indices.begin(), stripped_indices.end(), result.start_index);
+    size_t page_text_result_start_index =
+        result.start_index +
+        std::distance(stripped_indices.begin(), stripped_indices_begin);
+
+    // Need to convert the stripped page length into a page text length, since
+    // the matching range may have stripped characters within it. This
+    // conversion only cares about skipped characters in the result interval.
+    auto stripped_indices_end =
+        std::upper_bound(stripped_indices_begin, stripped_indices.end(),
+                         result.start_index + result.length);
+    int term_stripped_count =
+        std::distance(stripped_indices_begin, stripped_indices_end);
+    int page_text_result_length = result.length + term_stripped_count;
+
     // Need to map the indexes from the page text, which may have generated
     // characters like space etc, to character indices from the page.
     int text_to_start_searching_from = FPDFText_GetTextIndexFromCharIndex(
         pages_[current_page]->GetTextPage(), character_to_start_searching_from);
-    int temp_start = result.start_index + text_to_start_searching_from;
+    int temp_start =
+        page_text_result_start_index + text_to_start_searching_from;
     int start = FPDFText_GetCharIndexFromTextIndex(
         pages_[current_page]->GetTextPage(), temp_start);
     int end = FPDFText_GetCharIndexFromTextIndex(
-        pages_[current_page]->GetTextPage(), temp_start + result.length);
+        pages_[current_page]->GetTextPage(),
+        temp_start + page_text_result_length);
 
     // If |term| occurs at the end of a page, then |end| will be -1 due to the
     // index being out of bounds. Compensate for this case so the range
     // character count calculation below works out.
-    if (temp_start + result.length == original_text_length) {
+    if (temp_start + page_text_result_length == original_text_length) {
       DCHECK_EQ(-1, end);
       end = original_text_length;
     }
     DCHECK_LT(start, end);
-    DCHECK_EQ(term.size(), static_cast<size_t>(end - start));
+    DCHECK_EQ(term.size() + term_stripped_count,
+              static_cast<size_t>(end - start));
     AddFindResult(PDFiumRange(pages_[current_page].get(), start, end - start));
   }
 }
diff --git a/pdf/pdfium/pdfium_range.cc b/pdf/pdfium/pdfium_range.cc
index 5f10a5a..a89c428 100644
--- a/pdf/pdfium/pdfium_range.cc
+++ b/pdf/pdfium/pdfium_range.cc
@@ -23,6 +23,10 @@
 
 }  // namespace
 
+bool IsIgnorableCharacter(base::char16 c) {
+  return (c == kZeroWidthSpace) || (c == kPDFSoftHyphenMarker);
+}
+
 PDFiumRange::PDFiumRange(PDFiumPage* page, int char_index, int char_count)
     : page_(page), char_index_(char_index), char_count_(char_count) {
 #if DCHECK_IS_ON()
@@ -105,8 +109,7 @@
     api_string_adapter.Close(written);
   }
 
-  // Strip ignorable non-displaying whitespace
-  rv.erase(std::remove(rv.begin(), rv.end(), kZeroWidthSpace), rv.end());
+  base::EraseIf(rv, [](base::char16 c) { return IsIgnorableCharacter(c); });
 
   return rv;
 }
diff --git a/pdf/pdfium/pdfium_range.h b/pdf/pdfium/pdfium_range.h
index 56b0fca..80ab37e 100644
--- a/pdf/pdfium/pdfium_range.h
+++ b/pdf/pdfium/pdfium_range.h
@@ -14,6 +14,14 @@
 
 namespace chrome_pdf {
 
+constexpr base::char16 kZeroWidthSpace = 0x200B;
+constexpr base::char16 kPDFSoftHyphenMarker = 0xFFFE;
+
+// Helper for identifying characters that PDFium outputs, via FPDFText_GetText,
+// that have special meaning, but should not be included in things like copied
+// text or when running find.
+bool IsIgnorableCharacter(base::char16 c);
+
 // Describes location of a string of characters.
 class PDFiumRange {
  public:
diff --git a/pdf/test/data/spanner.pdf b/pdf/test/data/spanner.pdf
new file mode 100644
index 0000000..cf34cdb
--- /dev/null
+++ b/pdf/test/data/spanner.pdf
Binary files differ
diff --git a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
index 15f844a..683d875 100644
--- a/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
+++ b/services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.cc
@@ -70,7 +70,15 @@
 }
 
 void FrameCoordinationUnitImpl::SetLifecycleState(mojom::LifecycleState state) {
+  if (state == lifecycle_state_)
+    return;
+
+  mojom::LifecycleState old_state = lifecycle_state_;
   lifecycle_state_ = state;
+
+  if (process_coordination_unit_)
+    process_coordination_unit_->OnFrameLifecycleStateChanged(this, old_state);
+
   // The page will have the same lifecycle state as the main frame.
   if (IsMainFrame() && GetPageCoordinationUnit()) {
     // TODO(fdoray): Store the lifecycle state as a member on the
diff --git a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.cc b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.cc
index d855e86..0535fdc 100644
--- a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.cc
+++ b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.cc
@@ -31,7 +31,7 @@
   auto* frame_cu =
       FrameCoordinationUnitImpl::GetCoordinationUnitByID(graph_, cu_id);
   if (frame_cu)
-    AddFrame(frame_cu);
+    AddFrameImpl(frame_cu);
 }
 
 void ProcessCoordinationUnitImpl::SetCPUUsage(double cpu_usage) {
@@ -86,6 +86,18 @@
   return page_cus;
 }
 
+void ProcessCoordinationUnitImpl::OnFrameLifecycleStateChanged(
+    FrameCoordinationUnitImpl* frame_cu,
+    mojom::LifecycleState old_state) {
+  DCHECK(base::ContainsKey(frame_coordination_units_, frame_cu));
+  DCHECK_NE(old_state, frame_cu->lifecycle_state());
+
+  if (old_state == mojom::LifecycleState::kFrozen)
+    DecrementNumFrozenFrames();
+  else if (frame_cu->lifecycle_state() == mojom::LifecycleState::kFrozen)
+    IncrementNumFrozenFrames();
+}
+
 void ProcessCoordinationUnitImpl::OnEventReceived(mojom::Event event) {
   for (auto& observer : observers())
     observer.OnProcessEventReceived(this, event);
@@ -98,17 +110,40 @@
     observer.OnProcessPropertyChanged(this, property_type, value);
 }
 
-void ProcessCoordinationUnitImpl::AddFrame(
+void ProcessCoordinationUnitImpl::AddFrameImpl(
     FrameCoordinationUnitImpl* frame_cu) {
   const bool inserted = frame_coordination_units_.insert(frame_cu).second;
-  if (inserted)
+  if (inserted) {
     frame_cu->AddProcessCoordinationUnit(this);
+    if (frame_cu->lifecycle_state() == mojom::LifecycleState::kFrozen)
+      IncrementNumFrozenFrames();
+  }
 }
 
 void ProcessCoordinationUnitImpl::RemoveFrame(
     FrameCoordinationUnitImpl* frame_cu) {
   DCHECK(base::ContainsKey(frame_coordination_units_, frame_cu));
   frame_coordination_units_.erase(frame_cu);
+
+  if (frame_cu->lifecycle_state() == mojom::LifecycleState::kFrozen)
+    DecrementNumFrozenFrames();
+}
+
+void ProcessCoordinationUnitImpl::DecrementNumFrozenFrames() {
+  --num_frozen_frames_;
+  DCHECK_GE(num_frozen_frames_, 0);
+}
+
+void ProcessCoordinationUnitImpl::IncrementNumFrozenFrames() {
+  ++num_frozen_frames_;
+  DCHECK_LE(num_frozen_frames_,
+            static_cast<int>(frame_coordination_units_.size()));
+
+  if (num_frozen_frames_ ==
+      static_cast<int>(frame_coordination_units_.size())) {
+    for (auto& observer : observers())
+      observer.OnAllFramesInProcessFrozen(this);
+  }
 }
 
 }  // namespace resource_coordinator
diff --git a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h
index c1c5504..73ef2081 100644
--- a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h
+++ b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h
@@ -53,16 +53,24 @@
 
   base::ProcessId process_id() const { return process_id_; }
 
- private:
-  friend class FrameCoordinationUnitImpl;
+  // Removes |frame_cu| from the set of frames hosted by this process. Invoked
+  // from the destructor of FrameCoordinationUnitImpl.
+  void RemoveFrame(FrameCoordinationUnitImpl* frame_cu);
 
+  // Invoked when the state of a frame hosted by this process changes.
+  void OnFrameLifecycleStateChanged(FrameCoordinationUnitImpl* frame_cu,
+                                    mojom::LifecycleState old_state);
+
+ private:
   // CoordinationUnitInterface implementation.
   void OnEventReceived(mojom::Event event) override;
   void OnPropertyChanged(mojom::PropertyType property_type,
                          int64_t value) override;
 
-  void AddFrame(FrameCoordinationUnitImpl* frame_cu);
-  void RemoveFrame(FrameCoordinationUnitImpl* frame_cu);
+  void AddFrameImpl(FrameCoordinationUnitImpl* frame_cu);
+
+  void DecrementNumFrozenFrames();
+  void IncrementNumFrozenFrames();
 
   base::TimeDelta cumulative_cpu_usage_;
   uint64_t private_footprint_kb_ = 0u;
@@ -71,6 +79,9 @@
 
   std::set<FrameCoordinationUnitImpl*> frame_coordination_units_;
 
+  // The number of frames hosted by this process that are frozen.
+  int num_frozen_frames_ = 0;
+
   DISALLOW_COPY_AND_ASSIGN(ProcessCoordinationUnitImpl);
 };
 
diff --git a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl_unittest.cc b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl_unittest.cc
index 6524cb5..b2ceb510 100644
--- a/services/resource_coordinator/coordination_unit/process_coordination_unit_impl_unittest.cc
+++ b/services/resource_coordinator/coordination_unit/process_coordination_unit_impl_unittest.cc
@@ -3,7 +3,11 @@
 // found in the LICENSE file.
 
 #include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
+
 #include "services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h"
+#include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h"
+#include "services/resource_coordinator/coordination_unit/mock_coordination_unit_graphs.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace resource_coordinator {
@@ -12,6 +16,22 @@
 
 class ProcessCoordinationUnitImplTest : public CoordinationUnitTestHarness {};
 
+class MockCoordinationUnitGraphObserver : public CoordinationUnitGraphObserver {
+ public:
+  MockCoordinationUnitGraphObserver() = default;
+  virtual ~MockCoordinationUnitGraphObserver() = default;
+
+  bool ShouldObserve(const CoordinationUnitBase* coordination_unit) override {
+    return true;
+  }
+
+  MOCK_METHOD1(OnAllFramesInProcessFrozen,
+               void(const ProcessCoordinationUnitImpl*));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockCoordinationUnitGraphObserver);
+};
+
 }  // namespace
 
 TEST_F(ProcessCoordinationUnitImplTest, MeasureCPUUsage) {
@@ -23,4 +43,32 @@
   EXPECT_EQ(1, cpu_usage / 1000.0);
 }
 
+TEST_F(ProcessCoordinationUnitImplTest, OnAllFramesInProcessFrozen) {
+  auto owned_observer = std::make_unique<
+      testing::StrictMock<MockCoordinationUnitGraphObserver>>();
+  auto* observer = owned_observer.get();
+  coordination_unit_graph()->RegisterObserver(std::move(owned_observer));
+  MockMultiplePagesInSingleProcessCoordinationUnitGraph cu_graph(
+      coordination_unit_graph());
+
+  // 1/2 frame in the process is frozen.
+  // No call to OnAllFramesInProcessFrozen() is expected.
+  cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
+
+  // 2/2 frames in the process are frozen.
+  EXPECT_CALL(*observer, OnAllFramesInProcessFrozen(cu_graph.process.get()));
+  cu_graph.other_frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
+  testing::Mock::VerifyAndClear(observer);
+
+  // A frame is unfrozen and frozen.
+  cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kRunning);
+  EXPECT_CALL(*observer, OnAllFramesInProcessFrozen(cu_graph.process.get()));
+  cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
+  testing::Mock::VerifyAndClear(observer);
+
+  // A frozen frame is frozen again.
+  // No call to OnAllFramesInProcessFrozen() is expected.
+  cu_graph.frame->SetLifecycleState(mojom::LifecycleState::kFrozen);
+}
+
 }  // namespace resource_coordinator
diff --git a/services/resource_coordinator/observers/coordination_unit_graph_observer.h b/services/resource_coordinator/observers/coordination_unit_graph_observer.h
index 6d5efaa..078c33f4 100644
--- a/services/resource_coordinator/observers/coordination_unit_graph_observer.h
+++ b/services/resource_coordinator/observers/coordination_unit_graph_observer.h
@@ -91,6 +91,10 @@
       const SystemCoordinationUnitImpl* system_cu,
       const mojom::Event event) {}
 
+  // Called when all the frames in a process become frozen.
+  virtual void OnAllFramesInProcessFrozen(
+      const ProcessCoordinationUnitImpl* process_cu) {}
+
   void set_coordination_unit_graph(
       CoordinationUnitGraph* coordination_unit_graph) {
     coordination_unit_graph_ = coordination_unit_graph;
diff --git a/services/video_capture/BUILD.gn b/services/video_capture/BUILD.gn
index 84c11a8..f06fa73 100644
--- a/services/video_capture/BUILD.gn
+++ b/services/video_capture/BUILD.gn
@@ -87,6 +87,8 @@
     "test/mock_device_test.cc",
     "test/mock_device_test.h",
     "test/mock_device_unittest.cc",
+    "test/mock_devices_changed_observer.cc",
+    "test/mock_devices_changed_observer.h",
     "test/mock_producer.cc",
     "test/mock_producer.h",
     "test/mock_receiver.cc",
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 1cd5fc8e..36d2c712 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.cc
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -145,6 +145,11 @@
   NOTIMPLEMENTED();
 }
 
+void DeviceFactoryMediaToMojoAdapter::RegisterVirtualDevicesChangedObserver(
+    mojom::DevicesChangedObserverPtr observer) {
+  NOTIMPLEMENTED();
+}
+
 void DeviceFactoryMediaToMojoAdapter::CreateAndAddNewDevice(
     const std::string& device_id,
     mojom::DeviceRequest device_request,
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 65cde0d..0c785b7 100644
--- a/services/video_capture/device_factory_media_to_mojo_adapter.h
+++ b/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -43,6 +43,8 @@
   void AddTextureVirtualDevice(
       const media::VideoCaptureDeviceInfo& device_info,
       mojom::TextureVirtualDeviceRequest virtual_device) override;
+  void RegisterVirtualDevicesChangedObserver(
+      mojom::DevicesChangedObserverPtr observer) override;
 
  private:
   struct ActiveDeviceEntry {
diff --git a/services/video_capture/public/mojom/device_factory.mojom b/services/video_capture/public/mojom/device_factory.mojom
index e79248b..558c8dd 100644
--- a/services/video_capture/public/mojom/device_factory.mojom
+++ b/services/video_capture/public/mojom/device_factory.mojom
@@ -15,6 +15,10 @@
   ERROR_DEVICE_NOT_FOUND
 };
 
+interface DevicesChangedObserver {
+  OnDevicesChanged();
+};
+
 // Enables access to a set of video capture devices.
 // Typical operation is to first call GetDeviceInfos() to obtain
 // information about available devices. The |device_id| of the infos can
@@ -63,4 +67,10 @@
   AddTextureVirtualDevice(
       media.mojom.VideoCaptureDeviceInfo device_info,
       TextureVirtualDevice& virtual_device);
+
+  // Registered observers will get notified whenever a virtual device is added
+  // or removed. Note: Changes to non-virtual devices are currently being
+  // monitored outside the video capture service, and therefore the service
+  // does not offer such monitoring.
+  RegisterVirtualDevicesChangedObserver(DevicesChangedObserver observer);
 };
diff --git a/services/video_capture/test/device_factory_provider_test.cc b/services/video_capture/test/device_factory_provider_test.cc
index a652c3de..f4c664e 100644
--- a/services/video_capture/test/device_factory_provider_test.cc
+++ b/services/video_capture/test/device_factory_provider_test.cc
@@ -9,9 +9,18 @@
 #include "services/service_manager/public/mojom/constants.mojom.h"
 #include "services/service_manager/public/mojom/service_manager.mojom.h"
 #include "services/video_capture/public/mojom/constants.mojom.h"
+#include "services/video_capture/test/mock_producer.h"
 
 namespace video_capture {
 
+DeviceFactoryProviderTest::SharedMemoryVirtualDeviceContext::
+    SharedMemoryVirtualDeviceContext(mojom::ProducerRequest producer_request)
+    : mock_producer(
+          std::make_unique<MockProducer>(std::move(producer_request))) {}
+
+DeviceFactoryProviderTest::SharedMemoryVirtualDeviceContext::
+    ~SharedMemoryVirtualDeviceContext() = default;
+
 DeviceFactoryProviderTest::DeviceFactoryProviderTest()
     : service_manager::test::ServiceTest("video_capture_unittests") {}
 
@@ -33,4 +42,29 @@
   factory_provider_->ConnectToDeviceFactory(mojo::MakeRequest(&factory_));
 }
 
+std::unique_ptr<DeviceFactoryProviderTest::SharedMemoryVirtualDeviceContext>
+DeviceFactoryProviderTest::AddSharedMemoryVirtualDevice(
+    const std::string& device_id) {
+  media::VideoCaptureDeviceInfo device_info;
+  device_info.descriptor.device_id = device_id;
+  mojom::ProducerPtr producer;
+  auto result = std::make_unique<SharedMemoryVirtualDeviceContext>(
+      mojo::MakeRequest(&producer));
+  factory_->AddSharedMemoryVirtualDevice(
+      device_info, std::move(producer),
+      false /* send_buffer_handles_to_producer_as_raw_file_descriptors */,
+      mojo::MakeRequest(&result->device));
+  return result;
+}
+
+mojom::TextureVirtualDevicePtr
+DeviceFactoryProviderTest::AddTextureVirtualDevice(
+    const std::string& device_id) {
+  media::VideoCaptureDeviceInfo device_info;
+  device_info.descriptor.device_id = device_id;
+  mojom::TextureVirtualDevicePtr device;
+  factory_->AddTextureVirtualDevice(device_info, mojo::MakeRequest(&device));
+  return device;
+}
+
 }  // namespace video_capture
diff --git a/services/video_capture/test/device_factory_provider_test.h b/services/video_capture/test/device_factory_provider_test.h
index 16aa5857..4874e6e0 100644
--- a/services/video_capture/test/device_factory_provider_test.h
+++ b/services/video_capture/test/device_factory_provider_test.h
@@ -11,6 +11,8 @@
 
 namespace video_capture {
 
+class MockProducer;
+
 // Basic test fixture that sets up a connection to the fake device factory.
 class DeviceFactoryProviderTest : public service_manager::test::ServiceTest {
  public:
@@ -20,6 +22,20 @@
   void SetUp() override;
 
  protected:
+  struct SharedMemoryVirtualDeviceContext {
+    SharedMemoryVirtualDeviceContext(mojom::ProducerRequest producer_request);
+    ~SharedMemoryVirtualDeviceContext();
+
+    std::unique_ptr<MockProducer> mock_producer;
+    mojom::SharedMemoryVirtualDevicePtr device;
+  };
+
+  std::unique_ptr<SharedMemoryVirtualDeviceContext>
+  AddSharedMemoryVirtualDevice(const std::string& device_id);
+
+  mojom::TextureVirtualDevicePtr AddTextureVirtualDevice(
+      const std::string& device_id);
+
   mojom::DeviceFactoryProviderPtr factory_provider_;
   mojom::DeviceFactoryPtr factory_;
   base::MockCallback<mojom::DeviceFactory::GetDeviceInfosCallback>
diff --git a/services/video_capture/test/device_factory_provider_unittest.cc b/services/video_capture/test/device_factory_provider_unittest.cc
index ce19244..c01b11b 100644
--- a/services/video_capture/test/device_factory_provider_unittest.cc
+++ b/services/video_capture/test/device_factory_provider_unittest.cc
@@ -5,10 +5,11 @@
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/test/mock_callback.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "services/video_capture/public/mojom/constants.mojom.h"
 #include "services/video_capture/public/mojom/device_factory.mojom.h"
 #include "services/video_capture/test/device_factory_provider_test.h"
-#include "services/video_capture/test/mock_producer.h"
+#include "services/video_capture/test/mock_devices_changed_observer.h"
 
 using testing::_;
 using testing::Exactly;
@@ -56,13 +57,10 @@
 // when calling GetDeviceInfos.
 TEST_F(VideoCaptureServiceDeviceFactoryProviderTest,
        VirtualDeviceEnumeratedAfterAdd) {
-  base::RunLoop wait_loop;
   const std::string virtual_device_id = "/virtual/device";
-  media::VideoCaptureDeviceInfo info;
-  info.descriptor.device_id = virtual_device_id;
-  mojom::SharedMemoryVirtualDevicePtr virtual_device_proxy;
-  mojom::ProducerPtr producer_proxy;
-  MockProducer producer(mojo::MakeRequest(&producer_proxy));
+  auto device_context = AddSharedMemoryVirtualDevice(virtual_device_id);
+
+  base::RunLoop wait_loop;
   EXPECT_CALL(device_info_receiver_, Run(_))
       .Times(Exactly(1))
       .WillOnce(
@@ -78,14 +76,70 @@
             EXPECT_TRUE(virtual_device_enumerated);
             wait_loop.Quit();
           }));
-  factory_->AddSharedMemoryVirtualDevice(
-      info, std::move(producer_proxy),
-      false /* send_buffer_handles_to_producer_as_raw_file_descriptors */,
-      mojo::MakeRequest(&virtual_device_proxy));
   factory_->GetDeviceInfos(device_info_receiver_.Get());
   wait_loop.Run();
 }
 
+TEST_F(VideoCaptureServiceDeviceFactoryProviderTest,
+       AddingAndRemovingVirtualDevicesRaisesDevicesChangedEvent) {
+  mojom::DevicesChangedObserverPtr observer;
+  MockDevicesChangedObserver mock_observer;
+  mojo::Binding<mojom::DevicesChangedObserver> observer_binding(
+      &mock_observer, mojo::MakeRequest(&observer));
+  factory_->RegisterVirtualDevicesChangedObserver(std::move(observer));
+
+  std::unique_ptr<SharedMemoryVirtualDeviceContext> device_context_1;
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(mock_observer, OnDevicesChanged())
+        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+    device_context_1 = AddSharedMemoryVirtualDevice("TestDevice1");
+    run_loop.Run();
+  }
+
+  mojom::TextureVirtualDevicePtr device_context_2;
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(mock_observer, OnDevicesChanged())
+        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+    device_context_2 = AddTextureVirtualDevice("TestDevice2");
+    run_loop.Run();
+  }
+
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(mock_observer, OnDevicesChanged())
+        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+    device_context_1.reset();
+    run_loop.Run();
+  }
+
+  {
+    base::RunLoop run_loop;
+    EXPECT_CALL(mock_observer, OnDevicesChanged())
+        .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+    device_context_2.reset();
+    run_loop.Run();
+  }
+}
+
+// Tests that disconnecting a devices changed observer does not lead to any
+// crash or bad state.
+TEST_F(VideoCaptureServiceDeviceFactoryProviderTest,
+       AddAndRemoveVirtualDeviceAfterObserverHasDisconnected) {
+  mojom::DevicesChangedObserverPtr observer;
+  MockDevicesChangedObserver mock_observer;
+  mojo::Binding<mojom::DevicesChangedObserver> observer_binding(
+      &mock_observer, mojo::MakeRequest(&observer));
+  factory_->RegisterVirtualDevicesChangedObserver(std::move(observer));
+
+  // Disconnect observer
+  observer_binding.Close();
+
+  auto device_context = AddTextureVirtualDevice("TestDevice");
+  device_context = nullptr;
+}
+
 // Tests that VideoCaptureDeviceFactory::CreateDevice() returns an error
 // code when trying to create a device for an invalid descriptor.
 TEST_F(VideoCaptureServiceDeviceFactoryProviderTest,
@@ -112,22 +166,15 @@
        CreateDeviceSuccessForVirtualDevice) {
   base::RunLoop wait_loop;
   const std::string virtual_device_id = "/virtual/device";
-  media::VideoCaptureDeviceInfo info;
-  info.descriptor.device_id = virtual_device_id;
-  mojom::DevicePtr device_proxy;
-  mojom::SharedMemoryVirtualDevicePtr virtual_device_proxy;
-  mojom::ProducerPtr producer_proxy;
-  MockProducer producer(mojo::MakeRequest(&producer_proxy));
+  auto device_context = AddSharedMemoryVirtualDevice(virtual_device_id);
+
   base::MockCallback<mojom::DeviceFactory::CreateDeviceCallback>
       create_device_proxy_callback;
   EXPECT_CALL(create_device_proxy_callback,
               Run(mojom::DeviceAccessResultCode::SUCCESS))
       .Times(1)
       .WillOnce(InvokeWithoutArgs([&wait_loop]() { wait_loop.Quit(); }));
-  factory_->AddSharedMemoryVirtualDevice(
-      info, std::move(producer_proxy),
-      false /* send_buffer_handles_to_producer_as_raw_file_descriptors */,
-      mojo::MakeRequest(&virtual_device_proxy));
+  mojom::DevicePtr device_proxy;
   factory_->CreateDevice(virtual_device_id, mojo::MakeRequest(&device_proxy),
                          create_device_proxy_callback.Get());
   wait_loop.Run();
diff --git a/services/video_capture/test/mock_devices_changed_observer.cc b/services/video_capture/test/mock_devices_changed_observer.cc
new file mode 100644
index 0000000..d571f63
--- /dev/null
+++ b/services/video_capture/test/mock_devices_changed_observer.cc
@@ -0,0 +1,13 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/video_capture/test/mock_devices_changed_observer.h"
+
+namespace video_capture {
+
+MockDevicesChangedObserver::MockDevicesChangedObserver() = default;
+
+MockDevicesChangedObserver::~MockDevicesChangedObserver() = default;
+
+}  // namespace video_capture
diff --git a/services/video_capture/test/mock_devices_changed_observer.h b/services/video_capture/test/mock_devices_changed_observer.h
new file mode 100644
index 0000000..850dfc0
--- /dev/null
+++ b/services/video_capture/test/mock_devices_changed_observer.h
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_VIDEO_CAPTURE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
+#define SERVICES_VIDEO_CAPTURE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
+
+#include "services/video_capture/public/mojom/device_factory.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace video_capture {
+
+class MockDevicesChangedObserver : public mojom::DevicesChangedObserver {
+ public:
+  MockDevicesChangedObserver();
+  ~MockDevicesChangedObserver() override;
+
+  // mojom::DevicesChangedObserver
+  MOCK_METHOD0(OnDevicesChanged, void());
+};
+
+}  // namespace video_capture
+
+#endif  // SERVICES_VIDEO_CAPTURE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
diff --git a/services/video_capture/virtual_device_enabled_device_factory.cc b/services/video_capture/virtual_device_enabled_device_factory.cc
index 03cb1b7..092faff 100644
--- a/services/video_capture/virtual_device_enabled_device_factory.cc
+++ b/services/video_capture/virtual_device_enabled_device_factory.cc
@@ -157,6 +157,7 @@
                                   std::move(producer_binding));
   virtual_devices_by_id_.insert(
       std::make_pair(device_id, std::move(device_entry)));
+  EmitDevicesChangedEvent();
 }
 
 void VirtualDeviceEnabledDeviceFactory::AddTextureVirtualDevice(
@@ -183,6 +184,15 @@
                                   std::move(producer_binding));
   virtual_devices_by_id_.insert(
       std::make_pair(device_id, std::move(device_entry)));
+  EmitDevicesChangedEvent();
+}
+
+void VirtualDeviceEnabledDeviceFactory::RegisterVirtualDevicesChangedObserver(
+    mojom::DevicesChangedObserverPtr observer) {
+  observer.set_connection_error_handler(base::BindOnce(
+      &VirtualDeviceEnabledDeviceFactory::OnDevicesChangedObserverDisconnected,
+      weak_factory_.GetWeakPtr(), &observer));
+  devices_changed_observers_.push_back(std::move(observer));
 }
 
 void VirtualDeviceEnabledDeviceFactory::OnGetDeviceInfos(
@@ -202,6 +212,7 @@
         const std::string& device_id) {
   virtual_devices_by_id_.at(device_id).StopDevice();
   virtual_devices_by_id_.erase(device_id);
+  EmitDevicesChangedEvent();
 }
 
 void VirtualDeviceEnabledDeviceFactory::
@@ -210,4 +221,23 @@
   virtual_devices_by_id_.at(device_id).StopDevice();
 }
 
+void VirtualDeviceEnabledDeviceFactory::EmitDevicesChangedEvent() {
+  for (auto& observer : devices_changed_observers_)
+    observer->OnDevicesChanged();
+}
+
+void VirtualDeviceEnabledDeviceFactory::OnDevicesChangedObserverDisconnected(
+    mojom::DevicesChangedObserverPtr* observer) {
+  auto iter = std::find_if(
+      devices_changed_observers_.begin(), devices_changed_observers_.end(),
+      [observer](const mojom::DevicesChangedObserverPtr& entry) {
+        return &entry == observer;
+      });
+  if (iter == devices_changed_observers_.end()) {
+    DCHECK(false);
+    return;
+  }
+  devices_changed_observers_.erase(iter);
+}
+
 }  // namespace video_capture
diff --git a/services/video_capture/virtual_device_enabled_device_factory.h b/services/video_capture/virtual_device_enabled_device_factory.h
index 8761ec0..f753c00ca 100644
--- a/services/video_capture/virtual_device_enabled_device_factory.h
+++ b/services/video_capture/virtual_device_enabled_device_factory.h
@@ -37,6 +37,8 @@
   void AddTextureVirtualDevice(
       const media::VideoCaptureDeviceInfo& device_info,
       mojom::TextureVirtualDeviceRequest virtual_device) override;
+  void RegisterVirtualDevicesChangedObserver(
+      mojom::DevicesChangedObserverPtr observer) override;
 
  private:
   class VirtualDeviceEntry;
@@ -49,10 +51,14 @@
       const std::string& device_id);
   void OnVirtualDeviceConsumerConnectionErrorOrClose(
       const std::string& device_id);
+  void EmitDevicesChangedEvent();
+  void OnDevicesChangedObserverDisconnected(
+      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_;
+  std::vector<mojom::DevicesChangedObserverPtr> devices_changed_observers_;
 
   base::WeakPtrFactory<VirtualDeviceEnabledDeviceFactory> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(VirtualDeviceEnabledDeviceFactory);
diff --git a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
index 87ac642..781e20c 100644
--- a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
@@ -35,12 +35,12 @@
   out->request_presentation_feedback = data.request_presentation_feedback();
   out->root_background_color = data.root_background_color();
   out->min_page_scale_factor = data.min_page_scale_factor();
+  out->top_controls_height = data.top_controls_height();
+  out->top_controls_shown_ratio = data.top_controls_shown_ratio();
 
 #if defined(OS_ANDROID)
   out->max_page_scale_factor = data.max_page_scale_factor();
   out->root_overflow_y_hidden = data.root_overflow_y_hidden();
-  out->top_controls_height = data.top_controls_height();
-  out->top_controls_shown_ratio = data.top_controls_shown_ratio();
   out->bottom_controls_height = data.bottom_controls_height();
   out->bottom_controls_shown_ratio = data.bottom_controls_shown_ratio();
 #endif
diff --git a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
index 6dc5e4c..5fc6ce9 100644
--- a/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
+++ b/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
@@ -101,6 +101,16 @@
     return metadata.min_page_scale_factor;
   }
 
+  static float top_controls_height(
+      const viz::CompositorFrameMetadata& metadata) {
+    return metadata.top_controls_height;
+  }
+
+  static float top_controls_shown_ratio(
+      const viz::CompositorFrameMetadata& metadata) {
+    return metadata.top_controls_shown_ratio;
+  }
+
 #if defined(OS_ANDROID)
   static float max_page_scale_factor(
       const viz::CompositorFrameMetadata& metadata) {
@@ -117,16 +127,6 @@
     return metadata.root_overflow_y_hidden;
   }
 
-  static float top_controls_height(
-      const viz::CompositorFrameMetadata& metadata) {
-    return metadata.top_controls_height;
-  }
-
-  static float top_controls_shown_ratio(
-      const viz::CompositorFrameMetadata& metadata) {
-    return metadata.top_controls_shown_ratio;
-  }
-
   static float bottom_controls_height(
       const viz::CompositorFrameMetadata& metadata) {
     return metadata.bottom_controls_height;
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 0993a63..e33415f 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -620,13 +620,13 @@
   uint64_t begin_frame_ack_sequence_number = 0xdeadbeef;
   FrameDeadline frame_deadline(base::TimeTicks(), 4u, base::TimeDelta(), true);
   const float min_page_scale_factor = 3.5f;
+  const float top_bar_height(1234.5f);
+  const float top_bar_shown_ratio(1.0f);
 
 #if defined(OS_ANDROID)
   const float max_page_scale_factor = 4.6f;
   const gfx::SizeF root_layer_size(1234.5f, 5432.1f);
   const bool root_overflow_y_hidden = true;
-  const float top_bar_height(1234.5f);
-  const float top_bar_shown_ratio(1.0f);
   const float bottom_bar_height(1234.5f);
   const float bottom_bar_shown_ratio(1.0f);
   Selection<gfx::SelectionBound> selection;
@@ -656,13 +656,13 @@
   input.frame_token = frame_token;
   input.begin_frame_ack.sequence_number = begin_frame_ack_sequence_number;
   input.min_page_scale_factor = min_page_scale_factor;
+  input.top_controls_height = top_bar_height;
+  input.top_controls_shown_ratio = top_bar_shown_ratio;
 
 #if defined(OS_ANDROID)
   input.max_page_scale_factor = max_page_scale_factor;
   input.root_layer_size = root_layer_size;
   input.root_overflow_y_hidden = root_overflow_y_hidden;
-  input.top_controls_height = top_bar_height;
-  input.top_controls_shown_ratio = top_bar_shown_ratio;
   input.bottom_controls_height = bottom_bar_height;
   input.bottom_controls_shown_ratio = bottom_bar_shown_ratio;
   input.selection = selection;
@@ -694,13 +694,13 @@
   EXPECT_EQ(begin_frame_ack_sequence_number,
             output.begin_frame_ack.sequence_number);
   EXPECT_EQ(min_page_scale_factor, output.min_page_scale_factor);
+  EXPECT_EQ(top_bar_height, output.top_controls_height);
+  EXPECT_EQ(top_bar_shown_ratio, output.top_controls_shown_ratio);
 
 #if defined(OS_ANDROID)
   EXPECT_EQ(max_page_scale_factor, output.max_page_scale_factor);
   EXPECT_EQ(root_layer_size, output.root_layer_size);
   EXPECT_EQ(root_overflow_y_hidden, output.root_overflow_y_hidden);
-  EXPECT_EQ(top_bar_height, output.top_controls_height);
-  EXPECT_EQ(top_bar_shown_ratio, output.top_controls_shown_ratio);
   EXPECT_EQ(bottom_bar_height, output.bottom_controls_height);
   EXPECT_EQ(bottom_bar_shown_ratio, output.bottom_controls_shown_ratio);
   EXPECT_EQ(selection, output.selection);
diff --git a/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom b/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
index d514e55..ab78037 100644
--- a/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
+++ b/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
@@ -42,10 +42,8 @@
   [EnableIf=is_android]
   bool root_overflow_y_hidden;
 
-  [EnableIf=is_android]
   float top_controls_height;
 
-  [EnableIf=is_android]
   float top_controls_shown_ratio;
 
   [EnableIf=is_android]
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index dd29bb34..8016bc44a 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -629,6 +629,18 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "vr_common_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
+        "test": "vr_pixeltests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -1940,6 +1952,30 @@
             }
           ]
         },
+        "test": "vr_common_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Windows-10-15063"
+            }
+          ]
+        },
+        "test": "vr_pixeltests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "x86-64",
+              "os": "Windows-10-15063"
+            }
+          ]
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -3928,6 +3964,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "vr_pixeltests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
@@ -4692,6 +4734,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "vr_pixeltests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "webkit_unit_tests"
       },
       {
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter b/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter
index bb65115..ab9e88f 100644
--- a/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter
+++ b/testing/buildbot/filters/chromeos.single_process_mash.content_browsertests.filter
@@ -15,81 +15,6 @@
 -CompositedScrollingBrowserTest.Scroll3DTransformedScroller
 
 
-# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496
-# There are different timeouts due the same root cause above.
-
-# MainThreadFrameObserver::Wait() times out.
-# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496
--AccessibilityHitTestingBrowserTest.HitTestingWithPinchZoom
--AutoscrollBrowserTest.AutoscrollDirectionChangeAfterFullyScrolled
--AutoscrollBrowserTest.AutoscrollFlingGSBDeltaHints
--AutoscrollBrowserTest.WheelScrollingWorksAfterAutoscrollCancel
--BrowserSideFlingBrowserTest.TouchpadFling
--BrowserSideFlingBrowserTest.TouchscreenFling
--CompositorEventAckBrowserTest.MouseWheel
--CompositorEventAckBrowserTest.PassiveTouchStartBlockingTouchEnd
--CompositorEventAckBrowserTest.TouchStart
--CompositorEventAckBrowserTest.TouchStartDuringFling
--MainThreadEventQueueBrowserTest.MouseMove
--MainThreadEventQueueBrowserTest.TouchMove
--PointerLockBrowserTest.PointerLockEventRouting
--PointerLockBrowserTest.PointerLockWheelEventRouting
--PointerLockBrowserTest.PointerLockWidgetHidden
--RenderWidgetHostViewBrowserTestBase.CompositorWorksWhenReusingRenderer
--ScreenOrientationOOPIFBrowserTest.ScreenOrientation
--ScrollLatencyBrowserTest.ScrollLatencyNotRecordedIfGSUIgnored
--ScrollLatencyBrowserTest.SmoothWheelScroll
--SitePerProcessBrowserTest.*
--SitePerProcessGestureHitTestBrowserTest.*
--SitePerProcessHitTestBrowserTest.*
--SitePerProcessMouseWheelHitTestBrowserTest.*
--TouchpadPinchBrowserTest.*
--WheelEventListenerBrowserTest.DocumentMouseWheelEventListenersPassiveByDefault
--WheelEventListenerBrowserTest.DocumentWheelEventListenersPassiveByDefault
-
-# DevToolsVideoConsumerTest::WaitUntilFrameReceived() times out.
-# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496
--DevToolsVideoConsumerTest.SetMinAndMaxFramesChangesDimensions
-
-# SurfaceHitTestReadyNotifier::WaitForSurfaceReady() times out.
-# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496
--SitePerProcessBrowserTouchActionTest.*
--SitePerProcessEmulatedTouchBrowserTest.*
--SitePerProcessHighDPIHitTestBrowserTest.*
--SitePerProcessInternalsHitTestBrowserTest.*
--SitePerProcessNonIntegerScaleFactorHitTestBrowserTest.*
--TouchAccessibilityBrowserTest.TouchExplorationInCrossSiteIframe
-
-# RenderWidgetHostInputEventRouter::IsViewInMap() never true.
-# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496
--RenderWidgetHostTouchEmulatorBrowserTest.TouchEmulator
--TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.BasicSelectionIsolatedIframe/0
--TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.BasicSelectionIsolatedIframe/1
--TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.BasicSelectionIsolatedScrollMainframe/0
--TouchSelectionForCrossProcessFramesTests/TouchSelectionControllerClientAuraSiteIsolationTest.BasicSelectionIsolatedScrollMainframe/1
--WebContentsViewAuraTest.ContentWindowClose
-
-# RenderWidgetHostViewBrowserTest::WaitForCopySourceReady() times out.
-# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496
--GLAndSoftwareCompositing/*
-
-# RenderFrameSubmissionObserver::Wait()/WaitForAnyFrameSubmission() times out.
-# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496
--TouchActionBrowserTest.*
--TouchInputBrowserTest.*
-
-# RenderWidgetHostViewAura::CopyFromSurface crashes.
-# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496
--SnapshotBrowserTest.SingleWindowTest
--WebContentsViewAuraTest.ReplaceStateReloadPushState
--WebContentsViewAuraTest.ScreenshotForSwappedOutRenderViews
-
-# WebContentsVideoCaptureDeviceBrowserTest::WaitForFrameWithColor() times out.
-# RWHVAura::CreateDelegatedFrameHostClient skipped. https://crbug.com/877496
--WebContentsVideoCaptureDeviceBrowserTest.*
--WebContentsVideoCaptureDeviceBrowserTestP.*
-
-
 # DCHECK(!event->IsPointerEvent()) fail. https://crbug.com/884342
 -MouseLatencyBrowserTest.CoalescedMouseWheelsCorrectlyTerminated
 
@@ -100,24 +25,25 @@
 # -SitePerProcessHitTestBrowserTest.CrossProcessMouseEnterAndLeaveTest/1
 # -SitePerProcessInternalsHitTestBrowserTest.NestedLocalNonFastScrollableDivCoordsAreLocal/3
 # -SitePerProcessNonIntegerScaleFactorHitTestBrowserTest.NestedSurfaceHitTestTest/1
+-SitePerProcessBrowserTouchActionTest.*
+-SitePerProcessEmulatedTouchBrowserTest.*
+-SitePerProcessGestureHitTestBrowserTest.*
+-SitePerProcessHighDPIHitTestBrowserTest.*
+-SitePerProcessHitTestBrowserTest.*
+-SitePerProcessInternalsHitTestBrowserTest.*
+-SitePerProcessMouseWheelHitTestBrowserTest.*
+-SitePerProcessNonIntegerScaleFactorHitTestBrowserTest.*
+-TouchAccessibilityBrowserTest.*
+-TouchSelectionForCrossProcessFramesTests/*
 
 
 # Hit test fails. https://crbug.com/884366
-# Leaving an example of the bug.
-# -SitePerProcessHitTestBrowserTest.HitTestNestedFrames/1
+-PointerLockBrowserTest.PointerLockEventRouting
+-PointerLockBrowserTest.PointerLockWheelEventRouting
+-SitePerProcessHitTestBrowserTest.*
 -SitePerProcessHitTestDataGenerationBrowserTest.*
 
 
 # ShowWidgetMessageFilter::Wait() times out. https://crbug.com/884369
 # Leaving an example of the bug.
 # -SitePerProcessHitTestBrowserTest.PopupMenuTest/1
-
-
-# TestTouchSelectionControllerClientAura::Wait() times out.
-# https://crbug.com/884389
--TouchSelectionControllerClientAuraScaleFactorTest.*
--TouchSelectionControllerClientAuraTest.*
-
-
-# The test times out. https://crbug.com/884393
--WebRtcCaptureFromElementBrowserTest.VerifyCanvasCaptureOffscreenCanvasFrames
diff --git a/testing/buildbot/filters/webui_polymer2_browser_tests.filter b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
index 387e218c..e6117fb 100644
--- a/testing/buildbot/filters/webui_polymer2_browser_tests.filter
+++ b/testing/buildbot/filters/webui_polymer2_browser_tests.filter
@@ -15,7 +15,6 @@
 # --gtest_repeat=5, but might pass on a single invocation).
 
 # Chrome Desktop failures (Mac, Linux, Windows).
--CrSettingsPeoplePageSyncAccountControlTest.All
 -MediaRouterElementsBrowserTest.MediaRouterContainerCastModeList
 -MediaRouterElementsBrowserTest.MediaRouterContainerFilterPart1
 -MediaRouterElementsBrowserTest.MediaRouterContainerFirstRunFlow
@@ -175,6 +174,7 @@
 CrSettingsPeoplePageChangePictureTest.*
 CrSettingsPeoplePageManageProfileTest.*
 CrSettingsPeoplePageSetupPinDialogTest.*
+CrSettingsPeoplePageSyncAccountControlTest.*
 CrSettingsPeoplePageSyncPageTest.*
 CrSettingsPeoplePageTest.*
 CrSettingsPersonalizationOptionsTest.*
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index 0676c33c..69838916 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -1286,23 +1286,10 @@
       'Win10 Tests x64',
     ],
   },
-  'vr_common_unittests': {
-    'remove_from': [
-      # chromium.win
-      'Win 7 Tests x64 (1)',
-      'Win10 Tests x64',
-    ],
-  },
-
   'vr_pixeltests': {
     'remove_from': [
       # chromium.fyi
       'VR Linux',
-      # chromium.win
-      'Win 7 Tests x64 (1)',
-      'Win10 Tests x64',
-      'Win7 Tests (1)',
-      'Win7 Tests (dbg)(1)',
     ],
   },
   'wayland_client_perftests': {
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index ca7b95d..0d14e9a 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -497,7 +497,6 @@
 crbug.com/591099 tables/mozilla/bugs/bug2973.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug50695-2.html [ Failure ]
 crbug.com/591099 tables/mozilla/bugs/bug55527.html [ Failure ]
-crbug.com/591099 tables/mozilla_expected_failures/bugs/bug3166-16.html [ Failure ]
 crbug.com/591099 transforms/3d/hit-testing/backface-no-transform-hit-test.html [ Failure ]
 crbug.com/591099 transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ]
 crbug.com/591099 transforms/3d/point-mapping/3d-point-mapping-origins.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 472ddb5..e06ff7c1 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -490,6 +490,9 @@
 ### virtual/layout_ng/fast/block/margin-collapse
 crbug.com/635619 [ Mac ] virtual/layout_ng/fast/block/margin-collapse/103.html [ Failure ]
 
+### virtual/layout_ng/fast/inline
+crbug.com/635619 [ Mac ] virtual/layout_ng/fast/inline/left-right-center-inline-alignment-in-ltr-and-rtl-blocks.html [ Failure ]
+
 ### virtual/layout_ng/overflow
 crbug.com/724701 virtual/layout_ng/overflow/overflow-basic-004.html [ Failure ]
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-tables/caption-writing-mode-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables/caption-writing-mode-001.html
new file mode 100644
index 0000000..835a5116
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-tables/caption-writing-mode-001.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<script src='/resources/testharness.js'></script>
+<script src='/resources/testharnessreport.js'></script>
+<link rel="author" title="David Grogan" href="dgrogan@chromium.org">
+<link rel="help" href="https://www.w3.org/TR/css-writing-modes-3/#orthogonal-flows">
+<meta name="flags" content="" />
+<meta name="assert" content="caption margins are resolved against table's height when table has vertical flow" />
+<style>
+x-table {
+  display: table;
+  width: 300px;
+  height: 200px;
+  writing-mode: vertical-lr;
+  outline: 2px dashed blue;
+}
+x-caption {
+  display: table-caption;
+  height: 50px;
+  width: 120px;
+  writing-mode: horizontal-tb;
+  outline: 1px solid black;
+}
+</style>
+
+<x-table>
+  <x-caption id=captionMarginLeft style="margin-left:20%">caption</x-caption>
+</x-table>
+<x-table>
+  <x-caption id=captionMarginTop style="margin:auto 0">caption</x-caption>
+</x-table>
+<p>This is a script test because of how ridiculously differently the current
+engines render these cases.</p>
+
+
+<script>
+let caption_margin_left = getComputedStyle(id=captionMarginLeft).marginLeft;
+test(() => assert_equals(caption_margin_left, "40px"), "Caption percent margins are resolved against table's height for vertical-lr tables");
+let caption_margin_top = getComputedStyle(captionMarginTop).marginTop;
+test(() => assert_equals(caption_margin_top, "75px"), "Caption with auto top/bottom margins is centered vertically for vertical-lr tables");
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
index b06cfa8..cb70d277 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-navigated-expected.txt
@@ -50,6 +50,8 @@
 PASS window.cached_navigator_mediaSession.playbackState is 'none'
 PASS window.cached_navigator_presentation.defaultRequest is null
 PASS window.cached_navigator_presentation.receiver is null
+PASS window.cached_navigator_serial.onconnect is null
+PASS window.cached_navigator_serial.ondisconnect is null
 PASS window.cached_navigator_serviceWorker.controller is null
 PASS window.cached_navigator_serviceWorker.oncontrollerchange is null
 PASS window.cached_navigator_serviceWorker.onmessage is null
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
index 764bbf2..a558dde 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-and-gced-expected.txt
@@ -50,6 +50,8 @@
 PASS window.cached_navigator_mediaSession.playbackState is 'none'
 PASS window.cached_navigator_presentation.defaultRequest is null
 PASS window.cached_navigator_presentation.receiver is null
+PASS window.cached_navigator_serial.onconnect is null
+PASS window.cached_navigator_serial.ondisconnect is null
 PASS window.cached_navigator_serviceWorker.controller is null
 PASS window.cached_navigator_serviceWorker.oncontrollerchange is null
 PASS window.cached_navigator_serviceWorker.onmessage is null
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
index 0ec08c7b..e2133f2 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-properties-after-frame-removed-expected.txt
@@ -50,6 +50,8 @@
 PASS window.cached_navigator_mediaSession.playbackState is 'none'
 PASS window.cached_navigator_presentation.defaultRequest is null
 PASS window.cached_navigator_presentation.receiver is null
+PASS window.cached_navigator_serial.onconnect is null
+PASS window.cached_navigator_serial.ondisconnect is null
 PASS window.cached_navigator_serviceWorker.controller is null
 PASS window.cached_navigator_serviceWorker.oncontrollerchange is null
 PASS window.cached_navigator_serviceWorker.onmessage is null
diff --git a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
index 24f37af..cd288669 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/Window/property-access-on-cached-window-after-frame-navigated-expected.txt
@@ -56,6 +56,8 @@
 PASS oldChildWindow.navigator.presentation.receiver is newChildWindow.navigator.presentation.receiver
 PASS oldChildWindow.navigator.product is newChildWindow.navigator.product
 PASS oldChildWindow.navigator.productSub is newChildWindow.navigator.productSub
+PASS oldChildWindow.navigator.serial.onconnect is newChildWindow.navigator.serial.onconnect
+PASS oldChildWindow.navigator.serial.ondisconnect is newChildWindow.navigator.serial.ondisconnect
 PASS oldChildWindow.navigator.serviceWorker.controller is newChildWindow.navigator.serviceWorker.controller
 PASS oldChildWindow.navigator.serviceWorker.oncontrollerchange is newChildWindow.navigator.serviceWorker.oncontrollerchange
 PASS oldChildWindow.navigator.serviceWorker.onmessage is newChildWindow.navigator.serviceWorker.onmessage
diff --git a/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime-expected.txt
deleted file mode 100644
index c11a9111..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-Tests that HTMLOptionsCollection does not keep its owner node alive.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS observeSelect.wasCollected is true
-PASS observeOption.wasCollected is true
-PASS observeOptions.wasCollected is false
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime.html b/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime.html
deleted file mode 100644
index 7592145..0000000
--- a/third_party/WebKit/LayoutTests/fast/dom/html-options-collection-lifetime.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<script src="../../resources/js-test.js"></script>
-<body>
-<script>
-description('Tests that HTMLOptionsCollection does not keep its owner node alive.');
-
-var select = document.createElement("select");
-var option = document.createElement("option");
-select.appendChild(option);
-var options = select.options;
-var observeSelect = internals.observeGC(select);
-var observeOption = internals.observeGC(option);
-var observeOptions = internals.observeGC(options);
-
-select = null;
-option = null;
-gc();
-
-shouldBeTrue('observeSelect.wasCollected');
-shouldBeTrue('observeOption.wasCollected');
-shouldBeFalse('observeOptions.wasCollected');
-</script>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/fast/layers/add-layer-with-nested-stacking-expected.png b/third_party/WebKit/LayoutTests/fast/layers/add-layer-with-nested-stacking-expected.png
index 6cda17ad..130b991b 100644
--- a/third_party/WebKit/LayoutTests/fast/layers/add-layer-with-nested-stacking-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/layers/add-layer-with-nested-stacking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/table/caption-margin-direction.html b/third_party/WebKit/LayoutTests/fast/table/caption-margin-direction.html
new file mode 100644
index 0000000..38a1b98
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/table/caption-margin-direction.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
+<style>
+body {
+  margin: 0px;
+}
+x-table {
+  display: table;
+  width: 300px;
+  outline: 2px dotted blue;
+}
+x-caption {
+  display: table-caption;
+  margin-left: 20px;
+  outline: 1px solid black;
+}
+</style>
+
+<p>When implementing table captions in NG, there was no goal to change behavior.
+This is a smoke test to ensure NG matches legacy when table captions's direction
+differ from their containing tables. This exact behavior can change when we
+implement table layout in NG, and probably should because Edge/FF treat captions
+differently in general.</p>
+
+<x-table>
+  <x-caption dir=rtl>Lorem ipsum dolor</x-caption>
+</x-table>
+
+<x-table dir=rtl>
+  <x-caption dir=ltr>Lorem ipsum dolor</x-caption>
+</x-table>
+
+<script>
+let captions = document.querySelectorAll("x-caption")
+let caption_num = 0;
+let expected_x = [0, 20];
+for (let i of captions) {
+  let rect = i.getBoundingClientRect();
+  test(() => assert_equals(rect.x, expected_x[caption_num++]), "Test caption location " + caption_num);
+}
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/block-no-inflow-children-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/block-no-inflow-children-expected.txt
index 4354dd5..4aef2c50 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/block-no-inflow-children-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/block-no-inflow-children-expected.txt
@@ -20,12 +20,7 @@
         {
           "object": "NGPhysicalTextFragment 'La la la la'",
           "rect": [0, 0, 62, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'La la la'",
-          "rect": [0, 0, 47, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-3509-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-3509-expected.txt
index bece1d3f..366cd570 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-3509-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-3509-expected.txt
@@ -20,22 +20,12 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='im'",
           "rect": [11, 131, 100, 100],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='im'",
-          "rect": [11, 131, 50, 100],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment '\u00A0'",
           "rect": [11, 131, 4, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u00A0'",
-          "rect": [11, 131, 4, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-5699-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-5699-expected.txt
index e7cc49e..a944ff4 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-5699-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-5699-expected.txt
@@ -20,22 +20,22 @@
         {
           "object": "NGPhysicalTextFragment 'Hello'",
           "rect": [8, 184, 35, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Hello'",
           "rect": [8, 156, 35, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment '\u00A0'",
           "rect": [8, 150, 4, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment '\u00A0'",
           "rect": [8, 136, 4, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt
index 5bf2fb40..5650d9c 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-6278-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [10, 138, 292, 160],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow DIV",
@@ -28,39 +28,39 @@
           "reason": "geometry"
         },
         {
-          "object": "NGPhysicalTextFragment 'fringilla orci nibh sed neque. Quisque eu nulla'",
+          "object": "NGPhysicalTextFragment 'vel fringilla orci nibh sed neque.'",
           "rect": [10, 178, 291, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment 'non nisi molestie accumsan. Etiam tellus urna,'",
+          "object": "NGPhysicalTextFragment 'Quisque eu nulla non nisi molestie'",
           "rect": [10, 198, 290, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment 'Phasellus vehicula, sem at posuere vehicula,'",
+          "object": "NGPhysicalTextFragment 'ac, laoreet non, suscipit sed, sapien.'",
           "rect": [10, 238, 278, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment 'laoreet ac, laoreet non, suscipit sed, sapien.'",
+          "object": "NGPhysicalTextFragment 'accumsan. Etiam tellus urna, laoreet'",
           "rect": [10, 218, 270, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment 'augue nibh molestie nisl, nec ullamcorper'",
+          "object": "NGPhysicalTextFragment 'Phasellus vehicula, sem at posuere'",
           "rect": [10, 258, 262, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment 'malesuada, est libero feugiat libero, vel'",
+          "object": "NGPhysicalTextFragment 'malesuada, est libero feugiat libero,'",
           "rect": [10, 158, 246, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [10, 138, 242, 200],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow DIV",
@@ -75,12 +75,7 @@
         {
           "object": "NGPhysicalTextFragment 'Curabitur pretium, quam quis semper'",
           "rect": [10, 138, 235, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Curabitur pretium, quam quis semper'",
-          "rect": [10, 138, 235, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'nec ullamcorper lacus ante vulputate'",
@@ -88,44 +83,9 @@
           "reason": "appeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'accumsan. Etiam tellus urna, laoreet'",
-          "rect": [10, 218, 227, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'ac, laoreet non, suscipit sed, sapien.'",
-          "rect": [10, 238, 224, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'malesuada, est libero feugiat libero,'",
-          "rect": [10, 158, 222, 19],
-          "reason": "appeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'vehicula, augue nibh molestie nisl,'",
           "rect": [10, 278, 217, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Phasellus vehicula, sem at posuere'",
-          "rect": [10, 258, 217, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Quisque eu nulla non nisi molestie'",
-          "rect": [10, 198, 217, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'vel fringilla orci nibh sed neque.'",
-          "rect": [10, 178, 203, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'lacus ante vulputate pede.'",
-          "rect": [10, 278, 162, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGTableCell TD id='col1'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-7235-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-7235-expected.txt
index ae0ad79..42f778e 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-7235-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/bugzilla-7235-expected.txt
@@ -25,12 +25,7 @@
         {
           "object": "NGPhysicalTextFragment '\u00A0'",
           "rect": [8, 156, 4, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u00A0'",
-          "rect": [8, 156, 4, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-expected.txt
index a182ed6c..37f42ba0 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-expected.txt
@@ -33,12 +33,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'",
           "rect": [0, 0, 100, 100],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'",
-          "rect": [0, 0, 100, 100],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-individual-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-individual-expected.txt
index a182ed6c..37f42ba0 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-individual-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-added-individual-expected.txt
@@ -33,12 +33,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'",
           "rect": [0, 0, 100, 100],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'",
-          "rect": [0, 0, 100, 100],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-expected.txt
index a3e1272..2dc02c3f 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-expected.txt
@@ -34,12 +34,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'",
           "rect": [0, 0, 100, 100],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'",
-          "rect": [0, 0, 100, 100],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-individual-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-individual-expected.txt
index 0760b24..2b3a86d1 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-individual-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/containing-block-removed-individual-expected.txt
@@ -35,12 +35,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'",
           "rect": [0, 0, 100, 100],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow (positioned) DIV id='container'",
-          "rect": [0, 0, 100, 100],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow (positioned) DIV class='fixed'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
index 534046b7..7df064b2 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -36,12 +36,7 @@
         {
           "object": "NGPhysicalTextFragment 'test1'",
           "rect": [8, 508, 29, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'test1'",
-          "rect": [8, 508, 29, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutView #document",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt
index c5998c4..fb89cd4 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/remove-inline-block-descendant-of-flex-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='inline-block-2' class='item'",
           "rect": [0, 200, 100, 100],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='inline-block-1' class='item'",
@@ -30,7 +30,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='inline-block-2' class='item'",
           "rect": [0, 100, 100, 100],
-          "reason": "appeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt
index c1cccda..67515c7 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/flexbox/repaint-expected.txt
@@ -30,77 +30,77 @@
         {
           "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
           "rect": [138, 168, 636, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
           "rect": [148, 168, 635, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
           "rect": [148, 168, 635, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
           "rect": [138, 128, 635, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
           "rect": [148, 128, 634, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean laoreet dolor id urna eleifend aliquet.'",
           "rect": [148, 128, 634, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
           "rect": [138, 188, 627, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
           "rect": [148, 188, 626, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis sapien, in condimentum leo neque sed'",
           "rect": [148, 188, 626, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
           "rect": [138, 148, 619, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
           "rect": [148, 148, 618, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
           "rect": [148, 148, 618, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
           "rect": [138, 208, 573, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
           "rect": [148, 208, 572, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
           "rect": [148, 208, 572, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow DIV id='content'",
@@ -113,9 +113,9 @@
           "reason": "incremental"
         },
         {
-          "object": "NGPhysicalTextFragment 'ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
+          "object": "NGPhysicalTextFragment 'nulla. Nunc quis porta elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id quam.'",
           "rect": [400, 208, 391, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'elit. Pellentesque erat lectus, ultricies a lobortis id, faucibus id'",
@@ -123,9 +123,9 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis'",
+          "object": "NGPhysicalTextFragment 'magnis dis parturient montes, nascetur ridiculus mus. Sed congue magna vitae dolor feugiat vehicula.'",
           "rect": [400, 168, 385, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'sapien, in condimentum leo neque sed nulla. Nunc quis porta'",
@@ -133,9 +133,9 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'Aenean laoreet dolor id urna eleifend aliquet. Nulla vel dolor'",
+          "object": "NGPhysicalTextFragment 'Nulla vel dolor ipsum. Aliquam ut turpis nisl, in vulputate sapien. Cum sociis natoque penatibus et'",
           "rect": [400, 148, 384, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Sed volutpat, tellus vel varius vestibulum, purus quam mollis'",
@@ -143,16 +143,6 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'natoque penatibus et magnis dis parturient montes, nascetur'",
-          "rect": [400, 188, 374, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'",
-          "rect": [400, 128, 347, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutNGBlockFlow DIV id='left'",
           "rect": [148, 128, 252, 180],
           "reason": "incremental"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/gradients-em-stops-repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/gradients-em-stops-repaint-expected.txt
index 2249e2cb..c499a4f 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/gradients-em-stops-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/gradients-em-stops-repaint-expected.txt
@@ -40,12 +40,7 @@
         {
           "object": "NGPhysicalTextFragment ' '",
           "rect": [330, 135, 4, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' '",
-          "rect": [330, 135, 4, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt
index 28e9da91..59be8f7 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/inline-reflow-expected.txt
@@ -20,47 +20,47 @@
         {
           "object": "NGPhysicalTextFragment 'AAAAA AAAA AAAA'",
           "rect": [0, 120, 300, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'A A A A A AA AA'",
           "rect": [0, 0, 300, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AA AA AA A A A'",
           "rect": [0, 160, 280, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AAA AAA AAA AA'",
           "rect": [0, 140, 280, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AAAAAA AAAAAAA'",
           "rect": [0, 80, 280, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AAA AAAA AAAA'",
           "rect": [0, 40, 260, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AA AA AAA AAA'",
           "rect": [0, 20, 260, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AAAAAA AAAAA'",
           "rect": [0, 100, 240, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AAAAA AAAAA'",
           "rect": [0, 60, 220, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AA AA AA A'",
@@ -78,29 +78,9 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'AAAA AAAAA'",
-          "rect": [0, 80, 200, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AA AAA AAA'",
-          "rect": [0, 40, 200, 20],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'A A A A A'",
           "rect": [0, 300, 180, 20],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'A A A A A'",
-          "rect": [0, 300, 180, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'A A A A A'",
-          "rect": [0, 0, 180, 20],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AAAA AAA'",
@@ -108,49 +88,14 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'AAA AAAA'",
-          "rect": [0, 60, 160, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AA AA AA'",
-          "rect": [0, 20, 160, 20],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'A A A A'",
           "rect": [0, 280, 140, 20],
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'AAAAAAA'",
-          "rect": [0, 140, 140, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAAAAA'",
-          "rect": [0, 160, 120, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAAAAA'",
-          "rect": [0, 120, 120, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAAAA'",
-          "rect": [0, 180, 100, 20],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'AAAAA'",
-          "rect": [0, 100, 100, 20],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'A A'",
-          "rect": [0, 180, 60, 20],
-          "reason": "appeared"
+          "rect": [0, 180, 100, 20],
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt
index 0692436b..bb2ed58 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-2-expected.txt
@@ -20,312 +20,282 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow P",
           "rect": [8, 74, 418, 526],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow P",
-          "rect": [8, 74, 418, 526],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
           "rect": [14, 541, 407, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
           "rect": [14, 540, 407, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
           "rect": [14, 521, 407, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
           "rect": [14, 520, 407, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
           "rect": [14, 581, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
           "rect": [14, 580, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
           "rect": [14, 561, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
           "rect": [14, 560, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
           "rect": [14, 341, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
           "rect": [14, 340, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
           "rect": [14, 321, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
           "rect": [14, 320, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
           "rect": [14, 301, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
           "rect": [14, 300, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
           "rect": [14, 281, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
           "rect": [14, 280, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
           "rect": [14, 261, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
           "rect": [14, 260, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
           "rect": [14, 221, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
           "rect": [14, 220, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
           "rect": [14, 201, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
           "rect": [14, 200, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
           "rect": [14, 481, 355, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
           "rect": [14, 480, 355, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
           "rect": [14, 461, 355, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
           "rect": [14, 460, 355, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
           "rect": [14, 160, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
           "rect": [14, 140, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
           "rect": [14, 120, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
           "rect": [14, 100, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
           "rect": [14, 80, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
           "rect": [65, 361, 306, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
           "rect": [65, 360, 306, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
           "rect": [65, 421, 305, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
           "rect": [65, 420, 305, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'The players all played at once without waiting'",
           "rect": [65, 401, 305, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'The players all played at once without waiting'",
           "rect": [65, 400, 305, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
           "rect": [14, 441, 289, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'for the hedgehogs; and in a very short time '",
           "rect": [14, 440, 289, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'head down, and was going to '",
           "rect": [14, 241, 230, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'head down, and was going to '",
           "rect": [14, 240, 230, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
           "rect": [14, 180, 225, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
           "rect": [14, 181, 222, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'begin again, it was very'",
           "rect": [243, 241, 178, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'begin again, it was very'",
           "rect": [243, 240, 178, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'about once in a minute.'",
           "rect": [14, 501, 147, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'about once in a minute.'",
           "rect": [14, 500, 147, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment ' twist itself round and'",
           "rect": [277, 180, 144, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment ' twist itself round and'",
           "rect": [279, 181, 142, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'game indeed.'",
           "rect": [65, 381, 85, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'game indeed.'",
           "rect": [65, 380, 85, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [302, 441, 68, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'the Queen'",
           "rect": [302, 440, 68, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'difficult'",
           "rect": [371, 361, 50, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'difficult'",
           "rect": [371, 360, 50, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow (floating) SPAN id='greenFloat'",
@@ -350,12 +320,7 @@
         {
           "object": "NGPhysicalTextFragment 'would'",
           "rect": [235, 180, 46, 20],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'would'",
-          "rect": [238, 180, 41, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "VerticalScrollbar",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
index bc4e148..4e005c89 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -20,22 +20,17 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow P",
           "rect": [8, 74, 418, 526],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow P",
-          "rect": [8, 74, 418, 526],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
           "rect": [14, 540, 407, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
+          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
           "rect": [14, 540, 407, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
@@ -43,99 +38,64 @@
           "reason": "appeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'Alice began to feel very uneasy: to be sure, she had not as yet'",
+          "object": "NGPhysicalTextFragment 'had any dispute with the Queen, but she knew that it might'",
           "rect": [14, 520, 407, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
           "rect": [14, 580, 406, 19],
-          "reason": "appeared"
+          "reason": "subtree"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'here; the great wonder is, that there\u2018s any one left alive!\u2019'",
+          "rect": [14, 580, 406, 19],
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'become of me? They\u2019re dreadfully fond of beheading people'",
-          "rect": [14, 580, 406, 19],
-          "reason": "disappeared"
+          "rect": [14, 560, 406, 19],
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
           "rect": [14, 560, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'happen any minute, \u2018and then,\u2019 thought she, \u2018what would'",
-          "rect": [14, 560, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
           "rect": [14, 340, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'getting up and walking off to other parts of the ground, Alice'",
-          "rect": [14, 340, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
           "rect": [14, 320, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog to, and, as the doubled-up soldiers were always'",
-          "rect": [14, 320, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
           "rect": [14, 300, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'a ridge or furrow in the way wherever she wanted to send the'",
-          "rect": [14, 300, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
           "rect": [14, 280, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'in the act of crawling away: besides all this, there was generally'",
-          "rect": [14, 280, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
           "rect": [14, 260, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'provoking to find that the hedgehog had unrolled itself, and was'",
-          "rect": [14, 260, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
           "rect": [14, 220, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'could not help bursting out laughing: and when she had got its'",
-          "rect": [14, 220, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
           "rect": [14, 200, 406, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'look up in her face, with such a puzzled expression that she'",
-          "rect": [14, 200, 406, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'passion, and went stamping about, and shouting \u2018Off'",
@@ -143,19 +103,19 @@
           "reason": "appeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'shouting \u2018Off with his head!\u2019 or \u2018Off with her head!\u2019'",
+          "object": "NGPhysicalTextFragment 'minute.'",
           "rect": [14, 480, 355, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'with his head!\u2019 or \u2018Off with her head!\u2019 about once in a'",
           "rect": [14, 480, 355, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment 'was in a furious passion, and went stamping about, and'",
+          "object": "NGPhysicalTextFragment 'with his head!\u2019 or \u2018Off with her head!\u2019 about once in a'",
           "rect": [14, 460, 355, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'quarrelling all the while, and fighting for the hedgehogs;'",
@@ -165,52 +125,27 @@
         {
           "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
           "rect": [14, 160, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'neck nicely straightened out, and was going to give the'",
-          "rect": [14, 160, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
           "rect": [14, 140, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hanging down, but generally, just as she had got its'",
-          "rect": [14, 140, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
           "rect": [14, 120, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'away, comfortably enough, under her arm, with its legs'",
-          "rect": [14, 120, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
           "rect": [14, 100, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'her flamingo: she succeeded in getting its body tucked'",
-          "rect": [14, 100, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
           "rect": [14, 80, 354, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'The chief difficulty Alice found at first was in managing'",
-          "rect": [14, 80, 354, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'soon came to the conclusion that it was a very '",
@@ -223,9 +158,9 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'for turns, quarrelling all the while, and fighting'",
+          "object": "NGPhysicalTextFragment 'and in a very short time '",
           "rect": [65, 420, 305, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'The players all played at once without waiting'",
@@ -245,37 +180,22 @@
         {
           "object": "NGPhysicalTextFragment 'head down, and was going to '",
           "rect": [14, 240, 230, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'head down, and was going to '",
-          "rect": [14, 240, 230, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
           "rect": [14, 180, 225, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'hedgehog a blow with its head, it '",
-          "rect": [14, 180, 225, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'begin again, it was very'",
           "rect": [243, 240, 178, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'begin again, it was very'",
-          "rect": [243, 240, 178, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'and in a very short time '",
           "rect": [14, 440, 171, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'about once in a minute.'",
@@ -285,12 +205,7 @@
         {
           "object": "NGPhysicalTextFragment ' twist itself round and'",
           "rect": [277, 180, 144, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' twist itself round and'",
-          "rect": [277, 180, 144, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment ' was in a furious'",
@@ -340,7 +255,7 @@
         {
           "object": "NGPhysicalTextFragment 'minute.'",
           "rect": [14, 500, 47, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'indeed.'",
@@ -350,12 +265,7 @@
         {
           "object": "NGPhysicalTextFragment 'would'",
           "rect": [238, 180, 41, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'would'",
-          "rect": [238, 180, 41, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/lines-with-layout-delta-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/lines-with-layout-delta-expected.txt
index 06d32f20..d67b02d 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/lines-with-layout-delta-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/lines-with-layout-delta-expected.txt
@@ -20,12 +20,7 @@
         {
           "object": "NGPhysicalTextFragment 'PASS'",
           "rect": [8, 58, 38, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'FAIL'",
-          "rect": [8, 58, 35, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-expected.txt
index 3ee6ef35..c1004c3 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-expected.txt
@@ -20,12 +20,12 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='outer'",
           "rect": [61, 537, 62, 37],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='outer'",
           "rect": [61, 531, 62, 37],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow DIV class='outer'",
@@ -160,32 +160,32 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 504, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 498, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 465, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 459, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 426, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 420, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutBlockFlow DIV",
@@ -200,52 +200,52 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 177, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 171, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 138, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 132, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 99, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 93, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 60, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 54, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 21, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [67, 15, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGTableCell TD",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-right-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-right-expected.txt
index 38d59d5..1cf8fa6 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-right-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/float-overflow-right-expected.txt
@@ -20,12 +20,12 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='outer'",
           "rect": [677, 537, 62, 37],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='outer'",
           "rect": [677, 531, 62, 37],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow DIV class='outer'",
@@ -160,32 +160,32 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 504, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 498, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 465, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 459, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 426, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 420, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutBlockFlow DIV",
@@ -200,52 +200,52 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 177, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 171, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 138, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 132, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 99, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 93, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 60, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 54, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 21, 50, 10],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV",
           "rect": [683, 15, 50, 10],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutNGTableCell TD",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt
index 6d25268..9a35008 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/overflow/line-overflow-expected.txt
@@ -18,29 +18,19 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'velit. Integer sollicitudin nisi ut'",
-          "rect": [8, 182, 195, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'adipiscing, enim in scelerisque'",
-          "rect": [8, 102, 192, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'adipiscing, enim in scelerisque'",
-          "rect": [8, 102, 192, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'sollicitudin nisi ut urna blandit'",
-          "rect": [8, 182, 191, 19],
-          "reason": "appeared"
+          "rect": [8, 182, 195, 19],
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment 'at sagittis eros leo pulvinar'",
+          "object": "NGPhysicalTextFragment 'adipiscing, enim in scelerisque'",
+          "rect": [8, 102, 192, 19],
+          "reason": "subtree"
+        },
+        {
+          "object": "NGPhysicalTextFragment 'pulvinar velit. Integer'",
           "rect": [8, 162, 168, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'lacus, at sagittis eros leo'",
@@ -48,34 +38,19 @@
           "reason": "appeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'urna blandit convallis.'",
+          "object": "NGPhysicalTextFragment 'convallis.'",
           "rect": [8, 202, 139, 19],
-          "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'pulvinar velit. Integer'",
-          "rect": [8, 162, 136, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Cras faucibus. Nunc'",
           "rect": [8, 82, 129, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Cras faucibus. Nunc'",
-          "rect": [8, 82, 129, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'convallis, augue '",
           "rect": [8, 122, 106, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'convallis, augue'",
-          "rect": [8, 122, 102, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment ' eleifend lacus,'",
@@ -83,11 +58,6 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'convallis.'",
-          "rect": [8, 202, 60, 19],
-          "reason": "appeared"
-        },
-        {
           "object": "NGPhysicalTextFragment ' eleifend'",
           "rect": [149, 122, 54, 19],
           "reason": "appeared"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/inline-relative-positioned-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/inline-relative-positioned-expected.txt
index e442014..4c78beaa4 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/inline-relative-positioned-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/inline-relative-positioned-expected.txt
@@ -20,22 +20,12 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'",
           "rect": [8, 88, 100, 100],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'",
-          "rect": [8, 88, 100, 100],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'a'",
           "rect": [8, 88, 100, 100],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'p'",
-          "rect": [8, 88, 100, 100],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/layout-state-relative-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/layout-state-relative-expected.txt
index cade5a7..b8eaf48f 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/layout-state-relative-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/layout-state-relative-expected.txt
@@ -20,12 +20,7 @@
         {
           "object": "NGPhysicalTextFragment 'PASS'",
           "rect": [8, 152, 38, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'FAIL'",
-          "rect": [8, 152, 35, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/positioned-document-element-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/positioned-document-element-expected.txt
index 385babf..10591c3 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/positioned-document-element-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/position/positioned-document-element-expected.txt
@@ -25,12 +25,12 @@
         {
           "object": "NGPhysicalTextFragment 'Tests that the entire viewport is painted with a floated html element.'",
           "rect": [108, 116, 424, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Tests that the entire viewport is painted with a floated html element.'",
           "rect": [8, 16, 424, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/push-block-with-first-line-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/push-block-with-first-line-expected.txt
index 1d053c6..c579c1b 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/push-block-with-first-line-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/push-block-with-first-line-expected.txt
@@ -20,22 +20,22 @@
         {
           "object": "NGPhysicalBoxFragment LayoutInline (anonymous)",
           "rect": [8, 68, 140, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'JOCULAR'",
           "rect": [8, 68, 140, 20],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutInline (anonymous)",
           "rect": [8, 8, 140, 20],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'JOCULAR'",
           "rect": [8, 8, 140, 20],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/quotes-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/quotes-expected.txt
index e0d2e56..1cf08b7 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/quotes-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/quotes-expected.txt
@@ -20,32 +20,27 @@
         {
           "object": "NGPhysicalTextFragment 'quote 2'",
           "rect": [17, 28, 47, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'quote 2'",
           "rect": [16, 28, 47, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment '\u003E'",
+          "object": "NGPhysicalTextFragment '}'",
           "rect": [64, 28, 9, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalTextFragment '\u003C'",
+          "object": "NGPhysicalTextFragment '{'",
           "rect": [8, 28, 9, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment '}'",
           "rect": [63, 28, 8, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment '{'",
-          "rect": [8, 28, 8, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-with-rotation-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-with-rotation-expected.txt
index 2993677a..84282575 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-with-rotation-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/reflection/reflection-with-rotation-expected.txt
@@ -20,22 +20,12 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'",
           "rect": [22, 50, 226, 167],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'",
-          "rect": [22, 50, 226, 167],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'PASS'",
           "rect": [23, 51, 72, 110],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'FAIL'",
-          "rect": [23, 51, 69, 109],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/remove-inline-after-layout-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/remove-inline-after-layout-expected.txt
index 997a52b..d8501e0 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/remove-inline-after-layout-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/remove-inline-after-layout-expected.txt
@@ -40,12 +40,7 @@
         {
           "object": "NGPhysicalTextFragment ' '",
           "rect": [108, 193, 4, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' '",
-          "rect": [108, 193, 4, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/resize-iframe-text-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/resize-iframe-text-expected.txt
index d3bb216..b011069 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/resize-iframe-text-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/resize-iframe-text-expected.txt
@@ -25,12 +25,7 @@
         {
           "object": "NGPhysicalTextFragment 'Test passes if you see \"Success\" after window resizes.'",
           "rect": [8, 8, 341, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Test passes if you see \"Success\" after window resizes.'",
-          "rect": [8, 8, 341, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow HTML",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt
index 5315e639..68aed29 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset-expected.txt
@@ -18,14 +18,9 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'before'",
-          "rect": [100, 120, 40, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'after'",
-          "rect": [100, 120, 29, 19],
-          "reason": "appeared"
+          "rect": [100, 120, 40, 19],
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt
index dc02775b..703745e5 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset2-expected.txt
@@ -18,14 +18,9 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'before'",
-          "rect": [102, 122, 40, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'after'",
-          "rect": [102, 122, 29, 19],
-          "reason": "appeared"
+          "rect": [102, 122, 40, 19],
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt
index a91b26a..7f3fde7 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/layout-state-scrolloffset3-expected.txt
@@ -18,14 +18,9 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'before'",
-          "rect": [100, 120, 34, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment 'after'",
-          "rect": [100, 120, 29, 19],
-          "reason": "appeared"
+          "rect": [100, 120, 34, 19],
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt
index 55f3ded..1004caf 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/line-in-scrolled-clipped-block-expected.txt
@@ -18,14 +18,9 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment '                         FAIL     .'",
-          "rect": [8, 8, 100, 19],
-          "reason": "disappeared"
-        },
-        {
           "object": "NGPhysicalTextFragment '                         PASS     .'",
           "rect": [8, 8, 100, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt
index 046b972..b9963ee2 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-body-appear-expected.txt
@@ -20,42 +20,22 @@
         {
           "object": "NGPhysicalTextFragment 'Bug 36461 - No vertical scrollbar after the CSS class change'",
           "rect": [124, 52, 383, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Bug 36461 - No vertical scrollbar after the CSS class change'",
-          "rect": [124, 52, 383, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'You should see both vertical and horizontal scrollbars.'",
           "rect": [8, 16, 340, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'You should see both vertical and horizontal scrollbars.'",
-          "rect": [8, 16, 340, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'This is the test for '",
           "rect": [8, 52, 116, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'This is the test for '",
-          "rect": [8, 52, 116, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment '.'",
           "rect": [507, 52, 4, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment '.'",
-          "rect": [507, 52, 4, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-delete-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-delete-expected.txt
index fd754cf..652e1ed 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-delete-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/scroll/overflow-scroll-delete-expected.txt
@@ -20,12 +20,7 @@
         {
           "object": "NGPhysicalTextFragment 'Passed'",
           "rect": [8, 136, 43, 17],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Failed'",
-          "rect": [8, 136, 39, 17],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt
index f4113aee..0244c652f 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-clear-expected.txt
@@ -20,27 +20,17 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='firstLine'",
           "rect": [8, 8, 100, 200],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='firstLine'",
-          "rect": [8, 8, 100, 100],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'FAIL: Test did'",
+          "object": "NGPhysicalTextFragment '\u00A0'",
           "rect": [8, 8, 97, 100],
-          "reason": "disappeared"
+          "reason": "selection"
         },
         {
           "object": "NGPhysicalTextFragment 'not run'",
           "rect": [8, 108, 49, 100],
           "reason": "disappeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u00A0'",
-          "rect": [8, 8, 8, 100],
-          "reason": "appeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/subtree-root-skipped-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/subtree-root-skipped-expected.txt
index d62bef6..bb8d30e 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/subtree-root-skipped-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/subtree-root-skipped-expected.txt
@@ -25,12 +25,7 @@
         {
           "object": "NGPhysicalTextFragment 'Selection is here'",
           "rect": [8, 30, 103, 19],
-          "reason": "chunk appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Selection is here'",
-          "rect": [8, 30, 103, 19],
-          "reason": "chunk disappeared"
+          "reason": "subtree"
         },
         {
           "object": "InlineTextBox 'PASS'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt
index 84b34ed5..a5251b5 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/absolute-sized-content-with-resources-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 52, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGRect rect",
@@ -33,11 +33,6 @@
           "reason": "paint property change"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 52, 102, 402],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutSVGRect rect",
           "rect": [17, 219, 84, 68],
           "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt
index 1750a47..b0ae2a6 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/object-sizing-no-width-height-change-content-box-size-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 8, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutEmbeddedObject object",
@@ -33,11 +33,6 @@
           "reason": "paint property change"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 8, 202, 402],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutSVGRoot svg",
           "rect": [9, 109, 200, 200],
           "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-expected.txt
index 697f1cd..754b7bd9 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 72, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGRect rect id='targetRect'",
@@ -31,11 +31,6 @@
           "object": "LayoutSVGRoot svg",
           "rect": [109, 73, 300, 400],
           "reason": "incremental"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 72, 102, 402],
-          "reason": "disappeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
index b4f0ce0..8d6d90d 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-content-with-resources-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 72, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGEllipse circle",
@@ -48,11 +48,6 @@
           "reason": "subtree"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 72, 102, 402],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutSVGRoot svg",
           "rect": [8, 154, 39, 238],
           "reason": "incremental"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt
index a614a650..8d51dcc0 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-deep-shadow-tree-content-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 72, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGContainer g id='targetUse'",
@@ -28,11 +28,6 @@
           "reason": "paint property change"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 72, 102, 402],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutSVGContainer g id='targetUse'",
           "rect": [59, 273, 50, 200],
           "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-image-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-image-expected.txt
index 47af164..74f9763 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-image-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-image-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 72, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGImage image",
@@ -31,11 +31,6 @@
           "object": "LayoutSVGRoot svg",
           "rect": [109, 73, 300, 400],
           "reason": "incremental"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 72, 102, 402],
-          "reason": "disappeared"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-inner-svg-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-inner-svg-expected.txt
index 00da7a5..0f22050 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-inner-svg-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-inner-svg-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 52, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGViewportContainer svg",
@@ -28,11 +28,6 @@
           "reason": "paint property change"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 52, 102, 402],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg",
           "rect": [13, 207, 92, 92],
           "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-expected.txt
index de82b6bb..691ecca 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 72, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGContainer use",
@@ -38,11 +38,6 @@
           "reason": "incremental"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 72, 102, 402],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutSVGContainer use",
           "rect": [59, 273, 50, 200],
           "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol-expected.txt
index 3c8a60d..0871040f 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-shadow-tree-content-with-symbol-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 72, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGViewportContainer svg id='targetSymbol'",
@@ -28,11 +28,6 @@
           "reason": "paint property change"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 72, 102, 402],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg id='targetSymbol'",
           "rect": [9, 223, 100, 100],
           "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-on-symbol-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-on-symbol-expected.txt
index 5a9dbe2..cee2e38c 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-on-symbol-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-on-symbol-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 52, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGViewportContainer svg id='gamesBorder'",
@@ -28,11 +28,6 @@
           "reason": "paint property change"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 52, 102, 402],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg id='gamesBorder'",
           "rect": [18, 211, 82, 83],
           "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-without-attributes-on-symbol-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-without-attributes-on-symbol-expected.txt
index 16083937..ccf8816 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-without-attributes-on-symbol-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/relative-sized-use-without-attributes-on-symbol-expected.txt
@@ -20,7 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 52, 402, 402],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutSVGViewportContainer svg id='gamesBorder'",
@@ -28,11 +28,6 @@
           "reason": "paint property change"
         },
         {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 52, 102, 402],
-          "reason": "disappeared"
-        },
-        {
           "object": "LayoutSVGViewportContainer svg id='gamesBorder'",
           "rect": [13, 207, 92, 92],
           "reason": "paint property change"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index d8c4ee1e..98809e7 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -20,22 +20,12 @@
         {
           "object": "NGPhysicalTextFragment 'pservers-pattern-01-b \u2190'",
           "rect": [208, 972, 173, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'pservers-pattern-01-b \u2190'",
-          "rect": [208, 972, 173, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment '\u2192 script-handle-01-b'",
           "rect": [427, 972, 150, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u2192 script-handle-01-b'",
-          "rect": [427, 972, 150, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalBoxFragment LayoutInline A",
@@ -55,22 +45,12 @@
         {
           "object": "NGPhysicalTextFragment ' '",
           "rect": [423, 972, 5, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' '",
-          "rect": [423, 972, 5, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment ' '",
           "rect": [380, 972, 5, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment ' '",
-          "rect": [380, 972, 5, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ],
       "transform": 1
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/svg-image-change-content-size-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/svg-image-change-content-size-expected.txt
index d16d1e6..24c5036 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/svg-image-change-content-size-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/svg/svg-image-change-content-size-expected.txt
@@ -20,12 +20,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
           "rect": [8, 52, 602, 422],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow div id='contentBox'",
-          "rect": [8, 52, 422, 422],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutImage img",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt
index ec37fdcc..cca9c8b 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-percent-size-cell-expected.txt
@@ -35,22 +35,22 @@
         {
           "object": "NGPhysicalTextFragment 'ROW2'",
           "rect": [3, 400, 46, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'ROW1'",
           "rect": [3, 161, 46, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'ROW2'",
           "rect": [3, 115, 46, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'ROW1'",
           "rect": [3, 66, 46, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-vertical-align-cell-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-vertical-align-cell-expected.txt
index 5e05214..a306b2df 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-vertical-align-cell-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-repaint-vertical-align-cell-expected.txt
@@ -20,12 +20,12 @@
         {
           "object": "NGPhysicalTextFragment 'MIDDLE'",
           "rect": [3, 280, 63, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'MIDDLE'",
           "rect": [3, 90, 63, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-row-repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-row-repaint-expected.txt
index 4eabd0a..1a9c202bb 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-row-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/resize-table-row-repaint-expected.txt
@@ -20,12 +20,12 @@
         {
           "object": "NGPhysicalTextFragment 'MIDDLE'",
           "rect": [3, 192, 63, 19],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'MIDDLE'",
           "rect": [3, 142, 63, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/table-collapsed-border-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/table-collapsed-border-expected.txt
index c0d3760..7e709bd 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/table-collapsed-border-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/table/table-collapsed-border-expected.txt
@@ -80,42 +80,22 @@
         {
           "object": "NGPhysicalTextFragment 'sit amet'",
           "rect": [23, 339, 49, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'sit amet'",
-          "rect": [23, 339, 49, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'sit amet'",
           "rect": [23, 155, 49, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'sit amet'",
-          "rect": [23, 155, 49, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Lorem'",
           "rect": [23, 295, 43, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Lorem'",
-          "rect": [23, 295, 43, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Lorem'",
           "rect": [23, 111, 43, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Lorem'",
-          "rect": [23, 111, 43, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'dolor'",
@@ -125,22 +105,12 @@
         {
           "object": "NGPhysicalTextFragment '\u00A0'",
           "rect": [17, 225, 4, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u00A0'",
-          "rect": [17, 225, 4, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment '\u00A0'",
           "rect": [17, 133, 4, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment '\u00A0'",
-          "rect": [17, 133, 4, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt
index 9ff61e6..9723c5a 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-append-dirty-lines-expected.txt
@@ -20,72 +20,37 @@
         {
           "object": "NGPhysicalTextFragment 'sagittis aliquam nunc. Nullam pharetra molestie eros. Donec tempus purus ut ligula. Phasellus non nisl. Etiam eu mauris.'",
           "rect": [8, 144, 756, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'sagittis aliquam nunc. Nullam pharetra molestie eros. Donec tempus purus ut ligula. Phasellus non nisl. Etiam eu mauris.'",
-          "rect": [8, 144, 756, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'laoreet feugiat. Phasellus mollis pulvinar mi. Etiam ut neque sed eros egestas laoreet. Vestibulum ullamcorper, nulla non'",
           "rect": [8, 84, 751, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'laoreet feugiat. Phasellus mollis pulvinar mi. Etiam ut neque sed eros egestas laoreet. Vestibulum ullamcorper, nulla non'",
-          "rect": [8, 84, 751, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'pellentesque cursus. Proin vitae nulla. Vivamus in ipsum. Etiam mi. Nam malesuada purus in sem. Sed eget elit vel erat'",
           "rect": [8, 64, 749, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'pellentesque cursus. Proin vitae nulla. Vivamus in ipsum. Etiam mi. Nam malesuada purus in sem. Sed eget elit vel erat'",
-          "rect": [8, 64, 749, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse placerat. Morbi tristique. Mauris eu lacus sed felis'",
           "rect": [8, 44, 744, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse placerat. Morbi tristique. Mauris eu lacus sed felis'",
-          "rect": [8, 44, 744, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'fermentum ut, tortor. Sed rhoncus. Quisque enim metus, luctus tincidunt, vestibulum eu, vestibulum eu, libero. Mauris'",
           "rect": [8, 124, 740, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'fermentum ut, tortor. Sed rhoncus. Quisque enim metus, luctus tincidunt, vestibulum eu, vestibulum eu, libero. Mauris'",
-          "rect": [8, 124, 740, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'feugiat molestie, mi lorem bibendum leo, ac gravida orci nunc nec nulla. Nunc nunc lorem, rhoncus et, rutrum ac,'",
           "rect": [8, 104, 713, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'feugiat molestie, mi lorem bibendum leo, ac gravida orci nunc nec nulla. Nunc nunc lorem, rhoncus et, rutrum ac,'",
-          "rect": [8, 104, 713, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Curabitur a velit.'",
           "rect": [8, 164, 106, 19],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'Curabitur a velit'",
-          "rect": [8, 164, 103, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt
index d21e8cb..67fffa9a 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/text-match-document-change-expected.txt
@@ -18,9 +18,9 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "NGPhysicalTextFragment 'To be changed: findme (Manual testing:'",
+          "object": "NGPhysicalTextFragment 'After change'",
           "rect": [18, 130, 251, 19],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'Find-in-page 'findme', then click here)'",
@@ -28,11 +28,6 @@
           "reason": "disappeared"
         },
         {
-          "object": "NGPhysicalTextFragment 'After change'",
-          "rect": [18, 130, 82, 19],
-          "reason": "appeared"
-        },
-        {
           "object": "VerticalScrollbar",
           "rect": [295, 102, 15, 400],
           "reason": "scroll control"
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/transform/transform-layout-repaint-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/transform/transform-layout-repaint-expected.txt
index e96fb00..cfe119e 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/transform/transform-layout-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/transform/transform-layout-repaint-expected.txt
@@ -20,22 +20,12 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'",
           "rect": [40, 50, 208, 118],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV id='target'",
-          "rect": [40, 50, 208, 118],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'PASS'",
           "rect": [52, 51, 43, 32],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalTextFragment 'FAIL'",
-          "rect": [52, 51, 40, 31],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt
index 5d62e69..afb9717 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos-expected.txt
@@ -25,12 +25,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
           "rect": [0, 0, 6, 250],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
-          "rect": [0, 0, 6, 250],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'",
@@ -68,12 +63,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
           "rect": [0, 0, 6, 250],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
-          "rect": [0, 0, 6, 250],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'",
@@ -116,12 +106,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
           "rect": [0, 0, 6, 600],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
-          "rect": [0, 0, 6, 250],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'",
@@ -169,12 +154,7 @@
         {
           "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
           "rect": [0, 0, 6, 600],
-          "reason": "appeared"
-        },
-        {
-          "object": "NGPhysicalBoxFragment LayoutNGBlockFlow DIV class='parent'",
-          "rect": [0, 0, 6, 600],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "LayoutNGBlockFlow (relative positioned) DIV class='child'",
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt
index 4531371..e7eba6e 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/window-resize/window-resize-vertical-writing-mode-expected.txt
@@ -135,52 +135,52 @@
         {
           "object": "NGPhysicalTextFragment 'GGGG HHHH IIII JJJJ'",
           "rect": [581, 8, 68, 561],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'GGGG HHHH IIII JJJJ'",
           "rect": [181, 8, 68, 561],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'KKKK LLLL MMMM'",
           "rect": [510, 8, 68, 560],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'KKKK LLLL MMMM'",
           "rect": [110, 8, 68, 560],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AAAA BBBB CCCC'",
           "rect": [723, 8, 68, 519],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'AAAA BBBB CCCC'",
           "rect": [323, 8, 68, 519],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'DDDD EEEE FFFF'",
           "rect": [652, 8, 68, 482],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'DDDD EEEE FFFF'",
           "rect": [252, 8, 68, 482],
-          "reason": "disappeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'NNNN'",
           "rect": [439, 8, 68, 172],
-          "reason": "appeared"
+          "reason": "subtree"
         },
         {
           "object": "NGPhysicalTextFragment 'NNNN'",
           "rect": [39, 8, 68, 172],
-          "reason": "disappeared"
+          "reason": "subtree"
         }
       ]
     }
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/sibling-positioning-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/sibling-positioning-expected.png
deleted file mode 100644
index 6928cbc..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/compositing/sibling-positioning-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.png
deleted file mode 100644
index b56cf3c..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.txt
index 1c4cbcc9..d787aec 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/clip/nestedTransparencyClip-expected.txt
@@ -6,8 +6,8 @@
       LayoutBlockFlow (anonymous) at (0,0) size 784x60
         LayoutText {#text} at (0,0) size 741x39
           text run at (0,0) width 741: "This test is for a bug we had with clipping transparency layers. The bug is visual, so the pixel test is more worthwhile."
-          text run at (0,20) width 644: "Below, \"Peach,\" \"Plum,\" and \"Pear\" should appear. Before, we were clipping out \"Plum\" and \"Pear.\""
-        LayoutBR {BR} at (644,35) size 0x0
+          text run at (0,20) width 643: "Below, \"Peach,\" \"Plum,\" and \"Pear\" should appear. Before, we were clipping out \"Plum\" and \"Pear.\""
+        LayoutBR {BR} at (643,35) size 0x0
         LayoutBR {BR} at (0,40) size 0x19
 layer at (8,68) size 784x20 transparent
   LayoutBlockFlow {DIV} at (0,60) size 784x20
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers-expected.png
deleted file mode 100644
index 0d0f2d7..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers2-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers2-expected.png
deleted file mode 100644
index c057c97..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/css/ZeroOpacityLayers2-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/dynamic/anonymous-block-layer-lost-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/dynamic/anonymous-block-layer-lost-expected.png
deleted file mode 100644
index f87d11b..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/dynamic/anonymous-block-layer-lost-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/layers/opacity-stacking-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/layers/opacity-stacking-expected.png
deleted file mode 100644
index 8f9b429..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/layers/opacity-stacking-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.png
deleted file mode 100644
index bbfd888..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.txt
index 7c34ca6..d6de78b7 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/table/multiple-captions-display-expected.txt
@@ -40,26 +40,26 @@
       text run at (26,0) width 74: "PASS: First"
       text run at (5,20) width 116: "Caption aligned to"
       text run at (29,40) width 68: "the bottom"
-layer at (10,172) size 228x20
-  LayoutBlockFlow (positioned) {caption} at (10,172) size 228x20
-    LayoutText {#text} at (0,0) size 228x19
-      text run at (0,0) width 228: "PASS: Caption with a fixed position"
+layer at (10,172) size 229x20
+  LayoutBlockFlow (positioned) {caption} at (10,172) size 229x20
+    LayoutText {#text} at (0,0) size 229x19
+      text run at (0,0) width 229: "PASS: Caption with a fixed position"
 layer at (8,8) size 126x40 transparent
   LayoutBlockFlow {caption} at (0,0) size 126x40
     LayoutText {#text} at (15,0) size 102x39
       text run at (15,0) width 96: "PASS: Caption"
       text run at (12,20) width 102: "with opacity 0.7"
-layer at (10,216) size 329x20 transparent
-  LayoutBlockFlow (positioned) {caption} at (10,216) size 329x20
-    LayoutText {#text} at (0,0) size 329x19
-      text run at (0,0) width 329: "PASS: Caption with a fixed position and opacity 0.6"
+layer at (10,216) size 330x20 transparent
+  LayoutBlockFlow (positioned) {caption} at (10,216) size 330x20
+    LayoutText {#text} at (0,0) size 330x19
+      text run at (0,0) width 330: "PASS: Caption with a fixed position and opacity 0.6"
 layer at (8,88) size 118x59 transparent
   LayoutInline {a} at (0,0) size 118x59
     LayoutText {#text} at (15,0) size 118x59
       text run at (15,0) width 96: "PASS: Caption"
       text run at (4,20) width 118: "with opacity 0.5 in"
       text run at (14,40) width 98: "one of its child."
-layer at (71,148) size 441x20 transparent
-  LayoutBlockFlow (positioned) {a} at (71,148) size 441x20
-    LayoutText {#text} at (0,0) size 441x19
-      text run at (0,0) width 441: "PASS: Caption with opacity 0.4 and fixed position of one of the child."
+layer at (71,148) size 442x20 transparent
+  LayoutBlockFlow (positioned) {a} at (71,148) size 442x20
+    LayoutText {#text} at (0,0) size 442x19
+      text run at (0,0) width 442: "PASS: Caption with opacity 0.4 and fixed position of one of the child."
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.png b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.png
deleted file mode 100644
index 8279354a..0000000
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.txt b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.txt
index 1e38f2329..75ac12ce 100644
--- a/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.txt
+++ b/third_party/WebKit/LayoutTests/flag-specific/enable-slimming-paint-v2/fast/text/complex-text-opacity-expected.txt
@@ -37,30 +37,29 @@
         LayoutText {#text} at (504,7) size 6x29
           text run at (504,7) width 6: " "
         LayoutText {#text} at (0,0) size 0x0
-      LayoutBlockFlow {DIV} at (0,82) size 784x30
-        LayoutInline {SPAN} at (0,0) size 53x29
-          LayoutText {#text} at (590,0) size 53x29
-            text run at (590,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-        LayoutText {#text} at (584,0) size 6x29
-          text run at (584,0) width 6 RTL: " "
-        LayoutText {#text} at (525,0) size 6x29
-          text run at (525,0) width 6 RTL: " "
-        LayoutText {#text} at (466,0) size 6x29
-          text run at (466,0) width 6 RTL: " "
-        LayoutText {#text} at (407,0) size 6x29
-          text run at (407,0) width 6 RTL: " "
-        LayoutText {#text} at (348,0) size 6x29
-          text run at (348,0) width 6 RTL: " "
-        LayoutText {#text} at (289,0) size 6x29
-          text run at (289,0) width 6 RTL: " "
-        LayoutText {#text} at (230,0) size 6x29
-          text run at (230,0) width 6 RTL: " "
-        LayoutText {#text} at (171,0) size 6x29
-          text run at (171,0) width 6 RTL: " "
-        LayoutText {#text} at (112,0) size 6x29
-          text run at (112,0) width 6 RTL: " "
-        LayoutText {#text} at (53,0) size 6x29
-          text run at (53,0) width 6 RTL: " "
+      LayoutBlockFlow {DIV} at (0,82) size 784x60
+        LayoutInline {SPAN} at (0,0) size 71x29
+          LayoutText {#text} at (693,0) size 71x29
+            text run at (693,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+        LayoutText {#text} at (687,0) size 6x29
+          text run at (687,0) width 6 RTL: " "
+        LayoutText {#text} at (610,0) size 6x29
+          text run at (610,0) width 6 RTL: " "
+        LayoutText {#text} at (533,0) size 6x29
+          text run at (533,0) width 6 RTL: " "
+        LayoutText {#text} at (456,0) size 6x29
+          text run at (456,0) width 6 RTL: " "
+        LayoutText {#text} at (379,0) size 6x29
+          text run at (379,0) width 6 RTL: " "
+        LayoutText {#text} at (302,0) size 6x29
+          text run at (302,0) width 6 RTL: " "
+        LayoutText {#text} at (225,0) size 6x29
+          text run at (225,0) width 6 RTL: " "
+        LayoutText {#text} at (148,0) size 6x29
+          text run at (148,0) width 6 RTL: " "
+        LayoutText {#text} at (71,0) size 6x29
+          text run at (71,0) width 6 RTL: " "
+        LayoutText {#text} at (0,0) size 0x0
         LayoutText {#text} at (0,0) size 0x0
 layer at (8,44) size 45x29 transparent
   LayoutInline {SPAN} at (0,0) size 45x29
@@ -102,43 +101,43 @@
   LayoutInline {SPAN} at (0,0) size 45x29
     LayoutText {#text} at (510,7) size 45x29
       text run at (510,7) width 45: "\x{916}\x{94B}\x{91C}\x{947}\x{902}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (531,0) size 53x29
-      text run at (531,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (472,0) size 53x29
-      text run at (472,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (413,0) size 53x29
-      text run at (413,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (354,0) size 53x29
-      text run at (354,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (295,0) size 53x29
-      text run at (295,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (236,0) size 53x29
-      text run at (236,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (177,0) size 53x29
-      text run at (177,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (118,0) size 53x29
-      text run at (118,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (59,0) size 53x29
-      text run at (59,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
-layer at (8,90) size 53x29 transparent
-  LayoutInline {SPAN} at (0,0) size 53x29
-    LayoutText {#text} at (0,0) size 53x29
-      text run at (0,0) width 53 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (616,0) size 71x29
+      text run at (616,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (539,0) size 71x29
+      text run at (539,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (462,0) size 71x29
+      text run at (462,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (385,0) size 71x29
+      text run at (385,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (308,0) size 71x29
+      text run at (308,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (231,0) size 71x29
+      text run at (231,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (154,0) size 71x29
+      text run at (154,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (77,0) size 71x29
+      text run at (77,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (0,0) size 71x29
+      text run at (0,0) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
+layer at (8,90) size 71x29 transparent
+  LayoutInline {SPAN} at (0,0) size 71x29
+    LayoutText {#text} at (0,30) size 71x29
+      text run at (0,30) width 71 RTL: "\x{64A}\x{624}\x{644}\x{645}\x{646}\x{64A}"
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
index f8f2536b..15ab539 100644
--- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/global-interface-listing-service-worker-expected.txt
@@ -3473,6 +3473,7 @@
     getter permissions
     getter platform
     getter product
+    getter serial
     getter storage
     getter usb
     getter userAgent
diff --git a/third_party/WebKit/LayoutTests/netinfo/gc-frame-listeners.html b/third_party/WebKit/LayoutTests/netinfo/gc-frame-listeners.html
index 0c601e27..b825cc4 100644
--- a/third_party/WebKit/LayoutTests/netinfo/gc-frame-listeners.html
+++ b/third_party/WebKit/LayoutTests/netinfo/gc-frame-listeners.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <head>
+<script src="../resources/gc.js"></script>
 <script src="../resources/js-test.js"></script>
 <script src="resources/netinfo_common.js"></script>
 </head>
@@ -31,22 +32,22 @@
     childConnection.addEventListener('typechange', callback);
 })();
 
-gc();
-(() => {childFrame.contentWindow.gc();})()
-shouldBeFalse('childFrameObserver.wasCollected');
-shouldBeFalse('childConnectionObserver.wasCollected');
-shouldBeFalse('callbackObserver.wasCollected');
+asyncGC().then(() => {
+  shouldBeFalse('childFrameObserver.wasCollected');
+  shouldBeFalse('childConnectionObserver.wasCollected');
+  shouldBeFalse('callbackObserver.wasCollected');
 
-// Access objects in an inner function to avoid references to objects
-// remaining live on this function's stack frame (http://crbug.com/595672/).
-(() => {document.body.removeChild(childFrame);})();
-(() => {childFrame = null;})();
-gc();
-shouldBeTrue('childFrameObserver.wasCollected');
-shouldBeTrue('childConnectionObserver.wasCollected');
-shouldBeTrue('callbackObserver.wasCollected');
+  document.body.removeChild(childFrame);
+  childFrame = null;
 
-finishJSTest();
+  return asyncGC();
+}).then(() => {
+  shouldBeTrue('childFrameObserver.wasCollected');
+  shouldBeTrue('childConnectionObserver.wasCollected');
+  shouldBeTrue('callbackObserver.wasCollected');
+
+  finishJSTest();
+});
 
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/layers/remove-layer-with-nested-stacking-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/layers/remove-layer-with-nested-stacking-expected.png
index a1f4763..9a8cc14 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/layers/remove-layer-with-nested-stacking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/layers/remove-layer-with-nested-stacking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/table/overflowHidden-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/table/overflowHidden-expected.png
index f5ef6c2..32c54d6 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/table/overflowHidden-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/table/overflowHidden-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index b32ef85..85d4f5d 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png
index 69192ad4..d46ec31 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png
index 4b8d324..3af4d8b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png
index 986a358a..1887e224 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png
index 3422961a..9d1dd316 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
index 69192ad4..d46ec31 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png
index 4b8d324..3af4d8b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png
index 986a358a..1887e224 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png
index 3422961a..9d1dd316 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.png
deleted file mode 100644
index 20c1f44..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
deleted file mode 100644
index 9dc59f4e..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x170
-  LayoutBlockFlow {HTML} at (0,0) size 800x170
-    LayoutBlockFlow {BODY} at (8,8) size 784x154
-      LayoutText {#text} at (0,0) size 0x0
-layer at (8,8) size 300x150
-  LayoutVideo {VIDEO} at (0,0) size 300x150
-layer at (8,8) size 300x150
-  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x150
-    LayoutBlockFlow {DIV} at (0,118) size 300x32
-layer at (8,8) size 300x108
-  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108
-layer at (8,126) size 300x32 scrollHeight 40
-  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
-    LayoutButton {INPUT} at (0,0) size 32x32
-    LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
-      LayoutBlockFlow (anonymous) at (0,0) size 23.36x32
-        LayoutText {#text} at (0,9) size 24x14
-          text run at (0,9) width 24: "0:07"
-    LayoutFlexibleBox {DIV} at (55.36,0) size 34.69x32 [color=#5A5A5A]
-      LayoutBlockFlow (anonymous) at (4,0) size 30.69x32
-        LayoutText {#text} at (0,9) size 31x14
-          text run at (0,9) width 31: "/ 0:07"
-    LayoutSlider {INPUT} at (108.05,15) size 80.95x2
-      LayoutFlexibleBox {DIV} at (0,0) size 80.95x2
-        LayoutBlockFlow {DIV} at (-18,-23) size 116.95x48
-          LayoutBlockFlow {DIV} at (80.95,0) size 36x48
-    LayoutButton {INPUT} at (207,0) size 32x32
-    LayoutSlider {INPUT} at (257,15) size 25x2
-      LayoutFlexibleBox {DIV} at (0,0) size 25x2
-        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
-          LayoutBlockFlow {DIV} at (25,0) size 36x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 8632660..e773d1c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png
index f5eb453..60349c2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png
index 58e0c726..ae76971 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png
index 6349b3fe..8cc5110 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png
index ed55197a1..d3317d4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
index f5eb453..60349c2 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png
index 58e0c726..ae76971 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png
index 6349b3fe..8cc5110 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png
index ed55197a1..d3317d4 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.12/virtual/video-surface-layer/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.png
deleted file mode 100644
index 20c1f44..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
deleted file mode 100644
index 9dc59f4e..0000000
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x170
-  LayoutBlockFlow {HTML} at (0,0) size 800x170
-    LayoutBlockFlow {BODY} at (8,8) size 784x154
-      LayoutText {#text} at (0,0) size 0x0
-layer at (8,8) size 300x150
-  LayoutVideo {VIDEO} at (0,0) size 300x150
-layer at (8,8) size 300x150
-  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x150
-    LayoutBlockFlow {DIV} at (0,118) size 300x32
-layer at (8,8) size 300x108
-  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108
-layer at (8,126) size 300x32 scrollHeight 40
-  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
-    LayoutButton {INPUT} at (0,0) size 32x32
-    LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
-      LayoutBlockFlow (anonymous) at (0,0) size 23.36x32
-        LayoutText {#text} at (0,9) size 24x14
-          text run at (0,9) width 24: "0:07"
-    LayoutFlexibleBox {DIV} at (55.36,0) size 34.69x32 [color=#5A5A5A]
-      LayoutBlockFlow (anonymous) at (4,0) size 30.69x32
-        LayoutText {#text} at (0,9) size 31x14
-          text run at (0,9) width 31: "/ 0:07"
-    LayoutSlider {INPUT} at (108.05,15) size 80.95x2
-      LayoutFlexibleBox {DIV} at (0,0) size 80.95x2
-        LayoutBlockFlow {DIV} at (-18,-23) size 116.95x48
-          LayoutBlockFlow {DIV} at (80.95,0) size 36x48
-    LayoutButton {INPUT} at (207,0) size 32x32
-    LayoutSlider {INPUT} at (257,15) size 25x2
-      LayoutFlexibleBox {DIV} at (0,0) size 25x2
-        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
-          LayoutBlockFlow {DIV} at (25,0) size 36x48
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/layers/remove-layer-with-nested-stacking-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/layers/remove-layer-with-nested-stacking-expected.png
index 415932d..ba79e8b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/layers/remove-layer-with-nested-stacking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/layers/remove-layer-with-nested-stacking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/table/overflowHidden-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/table/overflowHidden-expected.png
index 6c0e46ea..f2ff84c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/table/overflowHidden-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/table/overflowHidden-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 66559c4..6e13f8ee 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png
index dde8996..b985e1a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png
index cc6a03b..0862e85 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png
index af3dfcb7..e08b5ba 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png
index 58ac52c..2f29279 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/layers/remove-layer-with-nested-stacking-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/layers/remove-layer-with-nested-stacking-expected.png
index cf0cddf8..e9ccb63 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/layers/remove-layer-with-nested-stacking-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/layers/remove-layer-with-nested-stacking-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/table/overflowHidden-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/table/overflowHidden-expected.png
index c2f4564..6a149cfd 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/table/overflowHidden-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/table/overflowHidden-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index e06b88e..15254408 100644
--- a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png
index 90899719..fdefc931 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/audio-controls-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png
index 09cfc341..efe724818 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/controls-layout-direction-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png
index 960cb4e0..81bcf379 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/media-controls-clone-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png
index 51748e6b..99f13f1 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.png
deleted file mode 100644
index d9b7beff..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
deleted file mode 100644
index fb7f6a4..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-layer at (0,0) size 800x600
-  LayoutView at (0,0) size 800x600
-layer at (0,0) size 800x170
-  LayoutBlockFlow {HTML} at (0,0) size 800x170
-    LayoutBlockFlow {BODY} at (8,8) size 784x154
-      LayoutText {#text} at (0,0) size 0x0
-layer at (8,8) size 300x150
-  LayoutVideo {VIDEO} at (0,0) size 300x150
-layer at (8,8) size 300x150
-  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x150
-    LayoutBlockFlow {DIV} at (0,118) size 300x32
-layer at (8,8) size 300x108
-  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108
-layer at (8,126) size 300x32 scrollHeight 40
-  LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
-    LayoutButton {INPUT} at (0,0) size 32x32
-    LayoutFlexibleBox {DIV} at (32,0) size 17.73x32 [color=#5A5A5A]
-      LayoutBlockFlow (anonymous) at (0,0) size 17.73x32
-        LayoutText {#text} at (0,9) size 18x14
-          text run at (0,9) width 18: "0:07"
-    LayoutFlexibleBox {DIV} at (49.73,0) size 28.27x32 [color=#5A5A5A]
-      LayoutBlockFlow (anonymous) at (4,0) size 24.27x32
-        LayoutText {#text} at (0,9) size 25x14
-          text run at (0,9) width 25: "/ 0:07"
-    LayoutSlider {INPUT} at (96,15) size 89.13x2
-      LayoutFlexibleBox {DIV} at (0,0) size 89.13x2
-        LayoutBlockFlow {DIV} at (-18,-23) size 125.13x48
-          LayoutBlockFlow {DIV} at (89.13,0) size 36x48
-    LayoutButton {INPUT} at (203.13,0) size 32x32
-    LayoutSlider {INPUT} at (253.13,15) size 28.88x2
-      LayoutFlexibleBox {DIV} at (0,0) size 28.88x2
-        LayoutBlockFlow {DIV} at (-18,-23) size 64.88x48
-          LayoutBlockFlow {DIV} at (28.88,0) size 36x48
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
index ce030b6..3102855e8 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-dedicated-worker-expected.txt
@@ -1041,6 +1041,21 @@
 [Worker]     method formData
 [Worker]     method json
 [Worker]     method text
+[Worker] interface Serial : EventTarget
+[Worker]     attribute @@toStringTag
+[Worker]     getter onconnect
+[Worker]     getter ondisconnect
+[Worker]     method constructor
+[Worker]     method getPorts
+[Worker]     setter onconnect
+[Worker]     setter ondisconnect
+[Worker] interface SerialPort
+[Worker]     attribute @@toStringTag
+[Worker]     getter in
+[Worker]     getter out
+[Worker]     method close
+[Worker]     method constructor
+[Worker]     method open
 [Worker] interface ServiceWorkerRegistration : EventTarget
 [Worker]     attribute @@toStringTag
 [Worker]     getter active
@@ -3485,6 +3500,7 @@
 [Worker]     getter permissions
 [Worker]     getter platform
 [Worker]     getter product
+[Worker]     getter serial
 [Worker]     getter storage
 [Worker]     getter usb
 [Worker]     getter userAgent
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 0fc50c6..45157a1 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4693,6 +4693,7 @@
     getter presentation
     getter product
     getter productSub
+    getter serial
     getter serviceWorker
     getter storage
     getter usb
@@ -6944,6 +6945,22 @@
     attribute @@toStringTag
     getter error
     method constructor
+interface Serial : EventTarget
+    attribute @@toStringTag
+    getter onconnect
+    getter ondisconnect
+    method constructor
+    method getPorts
+    method requestPort
+    setter onconnect
+    setter ondisconnect
+interface SerialPort
+    attribute @@toStringTag
+    getter in
+    getter out
+    method close
+    method constructor
+    method open
 interface ServiceWorker : EventTarget
     attribute @@toStringTag
     getter onerror
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
index ba9b3d5..e47ddc02 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-shared-worker-expected.txt
@@ -3372,6 +3372,7 @@
 [Worker]     getter permissions
 [Worker]     getter platform
 [Worker]     getter product
+[Worker]     getter serial
 [Worker]     getter storage
 [Worker]     getter usb
 [Worker]     getter userAgent
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index aeb5c2a..739444e9 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -245,7 +245,6 @@
     "platform/web_encrypted_media_key_information.h",
     "platform/web_encrypted_media_request.h",
     "platform/web_encrypted_media_types.h",
-    "platform/web_file_system.h",
     "platform/web_file_system_type.h",
     "platform/web_file_utilities.h",
     "platform/web_float_point.h",
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index 60ab65d..ebb56c7 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -32,6 +32,7 @@
     "frame/find_in_page.mojom",
     "indexeddb/indexeddb.mojom",
     "leak_detector/leak_detector.mojom",
+    "loader/code_cache.mojom",
     "loader/navigation_predictor.mojom",
     "loader/pause_subresource_loading_handle.mojom",
     "loader/previews_resource_loading_hints.mojom",
diff --git a/third_party/blink/public/mojom/filesystem/file_system.mojom b/third_party/blink/public/mojom/filesystem/file_system.mojom
index 8a03eb6..d33a4ee 100644
--- a/third_party/blink/public/mojom/filesystem/file_system.mojom
+++ b/third_party/blink/public/mojom/filesystem/file_system.mojom
@@ -219,9 +219,7 @@
   // success.
   // TODO(https://crbug.com/878581): Add more options to this method to support
   //     multiple files, directories, "open" vs "save" dialogs, etc.
-  // TODO(https://crbug.com/873661): Make interface per frame/worker and remove
-  //     |render_frame_id|.
-  ChooseEntry(int32 render_frame_id) =>
+  ChooseEntry() =>
       (mojo_base.mojom.FileError error_code,
        array<FileSystemEntry> entries);
 };
diff --git a/third_party/blink/public/mojom/loader/code_cache.mojom b/third_party/blink/public/mojom/loader/code_cache.mojom
new file mode 100644
index 0000000..7bd7041
--- /dev/null
+++ b/third_party/blink/public/mojom/loader/code_cache.mojom
@@ -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.
+
+module blink.mojom;
+
+import "mojo/public/mojom/base/time.mojom";
+import "url/mojom/origin.mojom";
+import "url/mojom/url.mojom";
+
+// Interface to the code cache in the browser process. Renderer processes
+// can use this interface to persistently store and retrieve executable code
+// generated for a URL.
+interface CodeCacheHost {
+  // Requests that the browser cache |data| associated with |url| and
+  // |expected_response_time|.
+  DidGenerateCacheableMetadata(url.mojom.Url url,
+                               mojo_base.mojom.Time expected_response_time,
+                               array<uint8> data);
+
+  // TODO(crbug.com/867848) Pass the data as mojo data_pipe instead of
+  // array<unit8>.
+  FetchCachedCode(url.mojom.Url url) => (mojo_base.mojom.Time response_time,
+                                         array<uint8> data);
+
+  ClearCodeCacheEntry(url.mojom.Url url);
+
+  // Requests that the browser cache |data| for the specified CacheStorage entry.
+  // TODO(https://crbug.com/779444): Verify or remove |cache_storage_origin|.
+  // TODO(kinuko): Consider making the renderer-side code directly call into the
+  // origin's CacheStoragePtr.
+  DidGenerateCacheableMetadataInCacheStorage(
+      url.mojom.Url url, mojo_base.mojom.Time expected_response_time,
+      array<uint8> data, url.mojom.Origin cache_storage_origin,
+      string cache_storage_cache_name);
+};
diff --git a/third_party/blink/public/platform/platform.h b/third_party/blink/public/platform/platform.h
index 4128909..e98560a 100644
--- a/third_party/blink/public/platform/platform.h
+++ b/third_party/blink/public/platform/platform.h
@@ -102,7 +102,6 @@
 class WebCookieJar;
 class WebCrypto;
 class WebDatabaseObserver;
-class WebFileSystem;
 class WebGraphicsContext3DProvider;
 class WebImageCaptureFrameGrabber;
 class WebLocalFrame;
@@ -279,9 +278,6 @@
 
   // FileSystem ----------------------------------------------------------
 
-  // Must return non-null.
-  virtual WebFileSystem* FileSystem() { return nullptr; }
-
   // Return a filename-friendly identifier for an origin.
   virtual WebString FileSystemCreateOriginIdentifier(
       const WebSecurityOrigin& origin) {
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 379a9fe8..9ca5760a 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1995,6 +1995,10 @@
   kPaymentAddressLanguageCode = 2542,
   kDocumentDomainBlockedCrossOriginAccess = 2543,
   kDocumentDomainEnabledCrossOriginAccess = 2544,
+  kSerialGetPorts = 2545,
+  kSerialRequestPort = 2546,
+  kSerialPortOpen = 2547,
+  kSerialPortClose = 2548,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/public/platform/web_file_system.h b/third_party/blink/public/platform/web_file_system.h
deleted file mode 100644
index 87a373ac..0000000
--- a/third_party/blink/public/platform/web_file_system.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_FILE_SYSTEM_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_FILE_SYSTEM_H_
-
-#include "base/files/file.h"
-#include "mojo/public/cpp/system/message_pipe.h"
-#include "third_party/blink/public/platform/web_callbacks.h"
-#include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_file_system_type.h"
-#include "third_party/blink/public/platform/web_url.h"
-#include "third_party/blink/public/platform/web_vector.h"
-
-namespace blink {
-
-class WebFrame;
-
-class WebFileSystem {
- public:
-  struct FileSystemEntry {
-    WebString file_system_id;
-    WebString base_name;
-  };
-
-  // Prompts the user to select a file from the native filesystem. Returns an
-  // error code if something failed, or a list of the selected entries on
-  // success.
-  using ChooseEntryCallbacks =
-      WebCallbacks<WebVector<FileSystemEntry>, base::File::Error>;
-  virtual void ChooseEntry(WebFrame* frame,
-                           std::unique_ptr<ChooseEntryCallbacks>) = 0;
-
- protected:
-  virtual ~WebFileSystem() = default;
-};
-
-}  // namespace blink
-
-#endif
diff --git a/third_party/blink/public/web/web_dom_file_system.h b/third_party/blink/public/web/web_dom_file_system.h
index 77ed4b6..f277aed 100644
--- a/third_party/blink/public/web/web_dom_file_system.h
+++ b/third_party/blink/public/web/web_dom_file_system.h
@@ -31,7 +31,7 @@
 #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_DOM_FILE_SYSTEM_H_
 
 #include "third_party/blink/public/platform/web_common.h"
-#include "third_party/blink/public/platform/web_file_system.h"
+#include "third_party/blink/public/platform/web_file_system_type.h"
 #include "third_party/blink/public/platform/web_private_ptr.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
diff --git a/third_party/blink/public/web/web_frame_widget.h b/third_party/blink/public/web/web_frame_widget.h
index 5c1a414a..9837a3b 100644
--- a/third_party/blink/public/web/web_frame_widget.h
+++ b/third_party/blink/public/web/web_frame_widget.h
@@ -47,7 +47,16 @@
 
 class WebFrameWidget : public WebWidget {
  public:
-  BLINK_EXPORT static WebFrameWidget* Create(WebWidgetClient*, WebLocalFrame*);
+  // Makes a WebFrameWidget that wraps a pre-existing WebWidget from the
+  // RenderView/WebView, for a new local main frame.
+  BLINK_EXPORT static WebFrameWidget* CreateForMainFrame(
+      WebWidgetClient*,
+      WebLocalFrame* main_frame);
+  // Makes a WebFrameWidget that wraps a WebLocalFrame that is not a main frame,
+  // providing a WebWidget to interact with the child local root frame.
+  BLINK_EXPORT static WebFrameWidget* CreateForChildLocalRoot(
+      WebWidgetClient*,
+      WebLocalFrame* local_root);
 
   // Sets the visibility of the WebFrameWidget.
   // We still track page-level visibility, but additionally we need to notify a
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 7d18e0c..cb74488 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -47,7 +47,6 @@
 #include "third_party/blink/public/platform/web_content_security_policy_struct.h"
 #include "third_party/blink/public/platform/web_content_settings_client.h"
 #include "third_party/blink/public/platform/web_effective_connection_type.h"
-#include "third_party/blink/public/platform/web_file_system.h"
 #include "third_party/blink/public/platform/web_file_system_type.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/public/platform/web_loading_behavior_flag.h"
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn
index d289d9ec..92e43fd 100644
--- a/third_party/blink/renderer/core/BUILD.gn
+++ b/third_party/blink/renderer/core/BUILD.gn
@@ -2028,6 +2028,7 @@
     "layout/ng/ng_block_node_test.cc",
     "layout/ng/ng_column_layout_algorithm_test.cc",
     "layout/ng/ng_constraint_space_builder_test.cc",
+    "layout/ng/ng_fieldset_layout_algorithm_test.cc",
     "layout/ng/ng_inline_layout_test.cc",
     "layout/ng/ng_layout_test.h",
     "layout/ng/ng_length_utils_test.cc",
diff --git a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
index 9dc15cb..f74801ce 100644
--- a/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
+++ b/third_party/blink/renderer/core/animation/css_interpolation_types_map.cc
@@ -54,7 +54,7 @@
     const PropertyRegistry* registry,
     const Document& document)
     : registry_(registry) {
-  allow_all_animations_ = document.GetFrame()->IsFeatureEnabled(
+  allow_all_animations_ = document.GetFrame()->DeprecatedIsFeatureEnabled(
       blink::mojom::FeaturePolicyFeature::kAnimations);
 }
 
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index c085865c..7be10e9 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -6217,9 +6217,9 @@
   if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
     return true;
   }
-  if (!frame_ ||
-      frame_->IsFeatureEnabled(mojom::FeaturePolicyFeature::kDocumentWrite,
-                               ReportOptions::kReportOnFailure)) {
+  if (!frame_ || frame_->DeprecatedIsFeatureEnabled(
+                     mojom::FeaturePolicyFeature::kDocumentWrite,
+                     ReportOptions::kReportOnFailure)) {
     return true;
   }
 
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index 5421536..f701e233 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -2542,7 +2542,7 @@
   WebLocalFrame* local_frame = WebLocalFrame::CreateMainFrame(
       web_view, &web_frame_client, nullptr, nullptr);
   web_frame_client.Bind(local_frame);
-  blink::WebFrameWidget::Create(&web_widget_client, local_frame);
+  blink::WebFrameWidget::CreateForMainFrame(&web_widget_client, local_frame);
 
   WebGestureEvent event(WebInputEvent::kGestureTap, WebInputEvent::kNoModifiers,
                         WebInputEvent::GetStaticTimeStampForTests(),
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index 3b3ae4d..2ecc05c 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -746,7 +746,7 @@
     return;
 
   // If the feature is allowed, don't log a warning.
-  if (frame->IsFeatureEnabled(feature))
+  if (frame->DeprecatedIsFeatureEnabled(feature))
     return;
 
   // If the feature is disabled, log a warning but only if the request is from a
diff --git a/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc b/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc
index 3138b17..5fd0ecc 100644
--- a/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc
+++ b/third_party/blink/renderer/core/frame/device_single_window_event_controller.cc
@@ -98,7 +98,7 @@
     return false;
   return std::all_of(features.begin(), features.end(),
                      [frame](mojom::FeaturePolicyFeature feature) {
-                       return frame->IsFeatureEnabled(feature);
+                       return frame->DeprecatedIsFeatureEnabled(feature);
                      });
 }
 
diff --git a/third_party/blink/renderer/core/frame/frame.cc b/third_party/blink/renderer/core/frame/frame.cc
index 87c4fdd..6e74b71 100644
--- a/third_party/blink/renderer/core/frame/frame.cc
+++ b/third_party/blink/renderer/core/frame/frame.cc
@@ -256,8 +256,8 @@
              : UserGestureIndicator::ConsumeUserGesture();
 }
 
-bool Frame::IsFeatureEnabled(mojom::FeaturePolicyFeature feature,
-                             ReportOptions report_on_failure) const {
+bool Frame::DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature feature,
+                                       ReportOptions report_on_failure) const {
   FeaturePolicy* feature_policy = GetSecurityContext()->GetFeaturePolicy();
   // The policy should always be initialized before checking it to ensure we
   // properly inherit the parent policy.
@@ -266,7 +266,7 @@
   if (feature_policy->IsFeatureEnabled(feature))
     return true;
   if (report_on_failure == ReportOptions::kReportOnFailure)
-    ReportFeaturePolicyViolation(feature);
+    DeprecatedReportFeaturePolicyViolation(feature);
   return false;
 }
 
diff --git a/third_party/blink/renderer/core/frame/frame.h b/third_party/blink/renderer/core/frame/frame.h
index 3c1c079..9e2e1bf 100644
--- a/third_party/blink/renderer/core/frame/frame.h
+++ b/third_party/blink/renderer/core/frame/frame.h
@@ -230,11 +230,12 @@
   // Optionally sends a report to any registered reporting observers or
   // Report-To endpoints, via ReportFeaturePolicyViolation(), if the feature is
   // disabled.
-  bool IsFeatureEnabled(
+  // TODO(iclelland): Replace these with methods on SecurityContext/Document
+  bool DeprecatedIsFeatureEnabled(
       mojom::FeaturePolicyFeature,
       ReportOptions report_on_failure = ReportOptions::kDoNotReport) const;
-  virtual void ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature) const {
-  }
+  virtual void DeprecatedReportFeaturePolicyViolation(
+      mojom::FeaturePolicyFeature) const {}
 
   // Called to make a frame inert or non-inert. A frame is inert when there
   // is a modal dialog displayed within an ancestor frame, and this frame
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
index e0ab5fd..8ab6a37 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -179,7 +179,8 @@
 WebLocalFrameImpl* CreateLocalChild(WebLocalFrame& parent,
                                     WebTreeScopeType scope,
                                     TestWebFrameClient* client) {
-  auto owned_client = CreateDefaultClientIfNeeded(client);
+  std::unique_ptr<TestWebFrameClient> owned_client =
+      CreateDefaultClientIfNeeded(client);
   WebLocalFrameImpl* frame =
       ToWebLocalFrameImpl(parent.CreateLocalChild(scope, client, nullptr));
   client->Bind(frame, std::move(owned_client));
@@ -200,34 +201,33 @@
 
 WebLocalFrameImpl* CreateProvisional(WebRemoteFrame& old_frame,
                                      TestWebFrameClient* client) {
-  auto owned_client = CreateDefaultClientIfNeeded(client);
+  std::unique_ptr<TestWebFrameClient> owned_client =
+      CreateDefaultClientIfNeeded(client);
   WebLocalFrameImpl* frame =
       ToWebLocalFrameImpl(WebLocalFrame::CreateProvisional(
           client, nullptr, &old_frame, WebSandboxFlags::kNone,
           ParsedFeaturePolicy()));
   client->Bind(frame, std::move(owned_client));
   // Create a local root, if necessary.
-  std::unique_ptr<WebWidgetClient> owned_widget_client;
-  WebWidgetClient* widget_client = nullptr;
   if (!frame->Parent()) {
     // TODO(dcheng): The main frame widget currently has a special case.
     // Eliminate this once WebView is no longer a WebWidget.
-    widget_client = frame->ViewImpl()->Client()->WidgetClient();
+    WebWidgetClient* widget_client =
+        frame->ViewImpl()->Client()->WidgetClient();
+    WebFrameWidget::CreateForMainFrame(widget_client, frame);
   } else if (frame->Parent()->IsWebRemoteFrame()) {
-    owned_widget_client = std::make_unique<TestWebWidgetClient>();
-    widget_client = owned_widget_client.get();
+    auto widget_client = std::make_unique<TestWebWidgetClient>();
+    WebFrameWidget* frame_widget =
+        WebFrameWidget::CreateForChildLocalRoot(widget_client.get(), frame);
+    frame_widget->Resize(WebSize());
+    client->BindWidgetClient(std::move(widget_client));
   }
-  if (widget_client) {
-    WebFrameWidget::Create(widget_client, frame);
-    if (frame->Parent())
-      frame->FrameWidget()->Resize(WebSize());
-  }
-  client->BindWidgetClient(std::move(owned_widget_client));
   return frame;
 }
 
 WebRemoteFrameImpl* CreateRemote(TestWebRemoteFrameClient* client) {
-  auto owned_client = CreateDefaultClientIfNeeded(client);
+  std::unique_ptr<TestWebRemoteFrameClient> owned_client =
+      CreateDefaultClientIfNeeded(client);
   auto* frame = WebRemoteFrameImpl::Create(WebTreeScopeType::kDocument, client);
   client->Bind(frame, std::move(owned_client));
   return frame;
@@ -239,14 +239,16 @@
                                     WebFrame* previous_sibling,
                                     TestWebFrameClient* client,
                                     TestWebWidgetClient* widget_client) {
-  auto owned_client = CreateDefaultClientIfNeeded(client);
-  auto* frame = ToWebLocalFrameImpl(parent.CreateLocalChild(
+  std::unique_ptr<TestWebFrameClient> owned_client =
+      CreateDefaultClientIfNeeded(client);
+  WebLocalFrameImpl* frame = ToWebLocalFrameImpl(parent.CreateLocalChild(
       WebTreeScopeType::kDocument, name, WebSandboxFlags::kNone, client,
       nullptr, previous_sibling, ParsedFeaturePolicy(), properties, nullptr));
   client->Bind(frame, std::move(owned_client));
 
-  auto owned_widget_client = CreateDefaultClientIfNeeded(widget_client);
-  WebFrameWidget::Create(widget_client, frame);
+  std::unique_ptr<TestWebWidgetClient> owned_widget_client =
+      CreateDefaultClientIfNeeded(widget_client);
+  WebFrameWidget::CreateForChildLocalRoot(widget_client, frame);
   // Set an initial size for subframes.
   if (frame->Parent())
     frame->FrameWidget()->Resize(WebSize());
@@ -259,7 +261,8 @@
     const WebString& name,
     scoped_refptr<SecurityOrigin> security_origin,
     TestWebRemoteFrameClient* client) {
-  auto owned_client = CreateDefaultClientIfNeeded(client);
+  std::unique_ptr<TestWebRemoteFrameClient> owned_client =
+      CreateDefaultClientIfNeeded(client);
   auto* frame = ToWebRemoteFrameImpl(parent.CreateRemoteChild(
       WebTreeScopeType::kDocument, name, WebSandboxFlags::kNone,
       ParsedFeaturePolicy(), client, nullptr));
@@ -289,7 +292,8 @@
   if (update_settings_func)
     update_settings_func(web_view_->GetSettings());
 
-  auto owned_web_frame_client = CreateDefaultClientIfNeeded(web_frame_client);
+  std::unique_ptr<TestWebFrameClient> owned_web_frame_client =
+      CreateDefaultClientIfNeeded(web_frame_client);
   WebLocalFrame* frame = WebLocalFrame::CreateMainFrame(
       web_view_, web_frame_client, nullptr, opener);
   web_frame_client->Bind(frame, std::move(owned_web_frame_client));
@@ -299,7 +303,7 @@
   WebWidgetClient* web_widget_client = test_web_widget_client;
   if (!web_widget_client)
     web_widget_client = test_web_view_client_->WidgetClient();
-  blink::WebFrameWidget::Create(web_widget_client, frame);
+  blink::WebFrameWidget::CreateForMainFrame(web_widget_client, frame);
   // Set an initial size for subframes.
   if (frame->Parent())
     frame->FrameWidget()->Resize(WebSize());
@@ -338,7 +342,7 @@
 
   InitializeWebView(web_view_client, nullptr);
 
-  auto owned_web_remote_frame_client =
+  std::unique_ptr<TestWebRemoteFrameClient> owned_web_remote_frame_client =
       CreateDefaultClientIfNeeded(web_remote_frame_client);
   WebRemoteFrameImpl* frame = WebRemoteFrameImpl::CreateMainFrame(
       web_view_, web_remote_frame_client, nullptr);
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index 81ec5c9..345caf6 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -1441,7 +1441,7 @@
   return reporting_service_;
 }
 
-void LocalFrame::ReportFeaturePolicyViolation(
+void LocalFrame::DeprecatedReportFeaturePolicyViolation(
     mojom::FeaturePolicyFeature feature) const {
   if (!RuntimeEnabledFeatures::FeaturePolicyReportingEnabled())
     return;
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index 6a53c3dd..ef70673 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -372,7 +372,9 @@
 
   SmoothScrollSequencer& GetSmoothScrollSequencer();
 
-  void ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature) const override;
+  // TODO(iclelland): Replace this with a method on Document
+  void DeprecatedReportFeaturePolicyViolation(
+      mojom::FeaturePolicyFeature) const override;
 
  private:
   friend class FrameNavigationDisabler;
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
index aa6d50c69..eeee21c 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -104,26 +104,41 @@
 
 // WebFrameWidget ------------------------------------------------------------
 
-WebFrameWidget* WebFrameWidget::Create(WebWidgetClient* client,
-                                       WebLocalFrame* local_root) {
+WebFrameWidget* WebFrameWidget::CreateForMainFrame(WebWidgetClient* client,
+                                                   WebLocalFrame* main_frame) {
   DCHECK(client) << "A valid WebWidgetClient must be supplied.";
-  WebFrameWidgetBase* widget;
-  if (!local_root->Parent()) {
-    // Note: this isn't a leak, as the object has a self-reference that the
-    // caller needs to release by calling Close().
-    WebLocalFrameImpl& main_frame = ToWebLocalFrameImpl(*local_root);
-    DCHECK(main_frame.ViewImpl());
-    // Note: this can't DCHECK that the view's main frame points to
-    // |main_frame|, as provisional frames violate this precondition.
-    // TODO(dcheng): Remove the special bridge class for main frame widgets.
-    widget = new WebViewFrameWidget(*client, *main_frame.ViewImpl());
-  } else {
-    DCHECK(local_root->Parent()->IsWebRemoteFrame())
-        << "Only local roots can have web frame widgets.";
-    // Note: this isn't a leak, as the object has a self-reference that the
-    // caller needs to release by calling Close().
-    widget = WebFrameWidgetImpl::Create(*client);
-  }
+  DCHECK(!main_frame->Parent());  // This is the main frame.
+
+  // Grabs the WebViewImpl associated with the |main_frame|, which will then
+  // be wrapped by the WebViewFrameWidget, with calls being forwarded to the
+  // |main_frame|'s WebViewImpl.
+  // Note: this can't DCHECK that the view's main frame points to
+  // |main_frame|, as provisional frames violate this precondition.
+  WebLocalFrameImpl& main_frame_impl = ToWebLocalFrameImpl(*main_frame);
+  DCHECK(main_frame_impl.ViewImpl());
+  WebViewImpl& web_view_impl = *main_frame_impl.ViewImpl();
+
+  // Note: this isn't a leak, as the object has a self-reference that the
+  // caller needs to release by calling Close().
+  // TODO(dcheng): Remove the special bridge class for main frame widgets.
+  WebFrameWidgetBase* widget = new WebViewFrameWidget(*client, web_view_impl);
+  widget->BindLocalRoot(*main_frame);
+  return widget;
+}
+
+WebFrameWidget* WebFrameWidget::CreateForChildLocalRoot(
+    WebWidgetClient* client,
+    WebLocalFrame* local_root) {
+  DCHECK(client) << "A valid WebWidgetClient must be supplied.";
+  DCHECK(local_root->Parent());  // This is not the main frame.
+  // Frames whose direct ancestor is a remote frame are local roots. Verify this
+  // is one. Other frames should be using the widget for their nearest local
+  // root.
+  DCHECK(local_root->Parent()->IsWebRemoteFrame());
+
+  // Note: this isn't a leak, as the object has a self-reference that the
+  // caller needs to release by calling Close().
+  WebFrameWidgetBase* widget = WebFrameWidgetImpl::Create(*client);
   widget->BindLocalRoot(*local_root);
   return widget;
 }
diff --git a/third_party/blink/renderer/core/fullscreen/fullscreen.cc b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
index 8d0606f..a6f9e01 100644
--- a/third_party/blink/renderer/core/fullscreen/fullscreen.cc
+++ b/third_party/blink/renderer/core/fullscreen/fullscreen.cc
@@ -215,8 +215,8 @@
 
   // 2. If Feature Policy is enabled, return the policy for "fullscreen"
   // feature.
-  return frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kFullscreen,
-                                 report_on_failure);
+  return frame->DeprecatedIsFeatureEnabled(
+      mojom::FeaturePolicyFeature::kFullscreen, report_on_failure);
 }
 
 bool AllowedToRequestFullscreen(Document& document) {
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics.cc b/third_party/blink/renderer/core/html/anchor_element_metrics.cc
index b980a75b..7a2ec806 100644
--- a/third_party/blink/renderer/core/html/anchor_element_metrics.cc
+++ b/third_party/blink/renderer/core/html/anchor_element_metrics.cc
@@ -212,6 +212,7 @@
     const HTMLAnchorElement* anchor_element) {
   if (!base::FeatureList::IsEnabled(features::kRecordAnchorMetricsClicked) ||
       !anchor_element->Href().ProtocolIsInHTTPFamily() ||
+      !GetRootDocument(*anchor_element)->Url().ProtocolIsInHTTPFamily() ||
       !anchor_element->GetDocument().BaseURL().ProtocolIsInHTTPFamily()) {
     return base::nullopt;
   }
@@ -235,6 +236,7 @@
   DCHECK(document.GetFrame());
   if (!base::FeatureList::IsEnabled(features::kRecordAnchorMetricsVisible) ||
       document.ParentDocument() || !document.View() ||
+      !document.Url().ProtocolIsInHTTPFamily() ||
       !document.BaseURL().ProtocolIsInHTTPFamily()) {
     return;
   }
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc b/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
index e5a6bef..f318644 100644
--- a/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
+++ b/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
@@ -310,4 +310,44 @@
   EXPECT_GT(10.2, feature3.GetRatioDistanceRootBottom());
 }
 
+TEST_F(AnchorElementMetricsTest, AnchorFeatureInIframeNonHttp) {
+  SimRequest main_resource("content://example.com/page1", "text/html");
+  SimRequest iframe_resource("https://example.com/iframe.html", "text/html");
+  SimRequest image_resource("https://example.com/cat.png", "image/png");
+
+  LoadURL("content://example.com/page1");
+
+  main_resource.Complete(String::Format(
+      R"HTML(
+        <body style='margin: 0px'>
+        <div style='height: %dpx;'></div>
+        <iframe id='iframe' src='https://example.com/iframe.html'
+            style='width: 300px; height: %dpx;
+            border-style: none; padding: 0px; margin: 0px;'></iframe>
+        <div style='height: %dpx;'></div>
+        </body>)HTML",
+      2 * kViewportHeight, kViewportHeight / 2, 10 * kViewportHeight));
+
+  iframe_resource.Complete(String::Format(
+      R"HTML(
+    <body style='margin: 0px'>
+    <div style='height: %dpx;'></div>
+    <a id='anchor' href="https://example.com/page2">example</a>
+    <div style='height: %dpx;'></div>
+    </body>)HTML",
+      kViewportHeight / 2, 5 * kViewportHeight));
+
+  Element* iframe = GetDocument().getElementById("iframe");
+  HTMLIFrameElement* iframe_element = ToHTMLIFrameElement(iframe);
+  Frame* sub = iframe_element->ContentFrame();
+  LocalFrame* subframe = ToLocalFrame(sub);
+
+  Element* anchor = subframe->GetDocument()->getElementById("anchor");
+  HTMLAnchorElement* anchor_element = ToHTMLAnchorElement(anchor);
+
+  EXPECT_FALSE(
+      AnchorElementMetrics::MaybeReportClickedMetricsOnClick(anchor_element)
+          .has_value());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
index d67b997..b0f63fb 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator.cc
@@ -23,7 +23,6 @@
 #include "third_party/blink/renderer/platform/web_task_runner.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/time.h"
-#include "third_party/skia/include/core/SkColorSpaceXform.h"
 #include "third_party/skia/include/core/SkSurface.h"
 
 namespace blink {
@@ -234,42 +233,36 @@
         skia_image = SkImage::MakeFromRaster(src_data_, nullptr, nullptr);
       }
       DCHECK(skia_image->colorSpace());
-      skia_image = skia_image->makeColorSpace(blob_color_space);
       image_ = StaticBitmapImage::Create(skia_image);
+      image_ = image_->ConvertToColorSpace(blob_color_space,
+                                           skia_image->colorType());
+      skia_image = image_->PaintImageForCurrentFrame().GetSkImage();
     }
 
-    if (skia_image->peekPixels(&src_data_))
+    if (skia_image->peekPixels(&src_data_)) {
       static_bitmap_image_loaded_ = true;
 
-    // If the source image is 8 bit per channel but the blob is requested in
-    // 16 bpc PNG, we need to ensure the color type of the pixmap is
-    // kRGBA_F16_SkColorType to kick in 16 bit encoding in SkPngEncoder. Since
-    // SkPixmap only holds a pointer to data, we need a helper data member here.
-    if (mime_type_ == kMimeTypePng &&
-        encode_options_.pixelFormat() == kRGBA16ImagePixelFormatName &&
-        src_data_.colorType() == kN32_SkColorType) {
-      size_t data_length = src_data_.width() * src_data_.height() *
-                           SkColorTypeBytesPerPixel(kRGBA_F16_SkColorType);
-      png_16bit_data_helper_ = SkData::MakeUninitialized(data_length);
-      SkColorSpaceXform::ColorFormat src_format =
-          SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
-      if (kN32_SkColorType == kBGRA_8888_SkColorType)
-        src_format = SkColorSpaceXform::ColorFormat::kBGRA_8888_ColorFormat;
-      if (SkColorSpaceXform::Apply(
-              src_data_.colorSpace(),
-              SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat,
-              png_16bit_data_helper_->writable_data(), src_data_.colorSpace(),
-              src_format, src_data_.addr(),
-              src_data_.width() * src_data_.height(),
-              SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp)) {
+      // If the source image is 8 bit per channel but the blob is requested in
+      // 16 bpc PNG, we need to ensure the color type of the pixmap is
+      // kRGBA_F16_SkColorType to kick in 16 bit encoding in SkPngEncoder. Since
+      // SkPixmap only holds a pointer to data, we need a helper data member
+      // here.
+      if (mime_type_ == kMimeTypePng &&
+          encode_options_.pixelFormat() == kRGBA16ImagePixelFormatName &&
+          src_data_.colorType() == kN32_SkColorType) {
+        size_t data_length = src_data_.width() * src_data_.height() *
+                             SkColorTypeBytesPerPixel(kRGBA_F16_SkColorType);
+        png_16bit_data_helper_ = SkData::MakeUninitialized(data_length);
         SkImageInfo info = SkImageInfo::Make(
             src_data_.width(), src_data_.height(), kRGBA_F16_SkColorType,
             src_data_.alphaType(), src_data_.info().refColorSpace());
-        src_data_.reset(info, png_16bit_data_helper_->data(),
-                        info.minRowBytes());
+        SkPixmap src_data_f16(info, png_16bit_data_helper_->data(),
+                              info.minRowBytes());
+        src_data_.readPixels(src_data_f16);
+        src_data_ = src_data_f16;
+        skia_image = SkImage::MakeFromRaster(src_data_, nullptr, nullptr);
+        image_ = StaticBitmapImage::Create(skia_image);
       }
-      skia_image = SkImage::MakeFromRaster(src_data_, nullptr, nullptr);
-      image_ = StaticBitmapImage::Create(skia_image);
     }
   }
 
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
index 52892e8..bc915b3 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
+++ b/third_party/blink/renderer/core/html/canvas/canvas_async_blob_creator_test.cc
@@ -265,8 +265,6 @@
   // The maximum difference locally observed is 3.
   const unsigned uint8_color_tolerance = 5;
   const float f16_color_tolerance = 0.01;
-  // The maximum difference locally observed has the order of e^-6.
-  const float xyz_d50_color_space_component_tolerance = 0.001;
 
   for (auto color_space_param : color_space_params) {
     for (auto blob_mime_type : blob_mime_types) {
@@ -306,8 +304,7 @@
           bool compare_alpha = (blob_mime_type != "image/jpeg");
           ASSERT_TRUE(ColorCorrectionTestUtils::MatchSkImages(
               ref_image, decoded_img, uint8_color_tolerance,
-              f16_color_tolerance, xyz_d50_color_space_component_tolerance,
-              compare_alpha));
+              f16_color_tolerance, compare_alpha));
         }
       }
     }
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
index e365835..47970055 100644
--- a/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.cc
@@ -30,7 +30,9 @@
 #include "third_party/blink/renderer/core/html/forms/html_legend_element.h"
 #include "third_party/blink/renderer/core/html/html_collection.h"
 #include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/core/layout/layout_fieldset.h"
+#include "third_party/blink/renderer/core/layout/layout_block.h"
+#include "third_party/blink/renderer/core/layout/layout_object_factory.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
 
 namespace blink {
@@ -115,8 +117,13 @@
   return fieldset;
 }
 
-LayoutObject* HTMLFieldSetElement::CreateLayoutObject(const ComputedStyle&) {
-  return new LayoutFieldset(this);
+LayoutObject* HTMLFieldSetElement::CreateLayoutObject(
+    const ComputedStyle& style) {
+  return LayoutObjectFactory::CreateFieldset(*this, style);
+}
+
+bool HTMLFieldSetElement::ShouldForceLegacyLayout() const {
+  return !RuntimeEnabledFeatures::LayoutNGFieldsetEnabled();
 }
 
 HTMLLegendElement* HTMLFieldSetElement::Legend() const {
diff --git a/third_party/blink/renderer/core/html/forms/html_field_set_element.h b/third_party/blink/renderer/core/html/forms/html_field_set_element.h
index 7e19e79..3895f75 100644
--- a/third_party/blink/renderer/core/html/forms/html_field_set_element.h
+++ b/third_party/blink/renderer/core/html/forms/html_field_set_element.h
@@ -48,7 +48,7 @@
   bool IsEnumeratable() const override { return true; }
   bool SupportsFocus() const override;
   LayoutObject* CreateLayoutObject(const ComputedStyle&) override;
-  bool ShouldForceLegacyLayout() const final { return true; }
+  bool ShouldForceLegacyLayout() const final;
   const AtomicString& FormControlType() const override;
   bool RecalcWillValidate() const override { return false; }
   int tabIndex() const final;
diff --git a/third_party/blink/renderer/core/html/media/autoplay_policy.cc b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
index a3c2d7b..c06cabb4 100644
--- a/third_party/blink/renderer/core/html/media/autoplay_policy.cc
+++ b/third_party/blink/renderer/core/html/media/autoplay_policy.cc
@@ -122,7 +122,8 @@
       return true;
     }
 
-    if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kAutoplay)) {
+    if (!frame->DeprecatedIsFeatureEnabled(
+            mojom::FeaturePolicyFeature::kAutoplay)) {
       return false;
     }
   }
@@ -445,7 +446,8 @@
       break;
     }
 
-    if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kAutoplay))
+    if (!frame->DeprecatedIsFeatureEnabled(
+            mojom::FeaturePolicyFeature::kAutoplay))
       break;
   }
 }
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc
index ff797505..b931294 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -3805,20 +3805,16 @@
   }
 }
 
-unsigned HTMLMediaElement::webkitAudioDecodedByteCount() const {
+uint64_t HTMLMediaElement::webkitAudioDecodedByteCount() const {
   if (!GetWebMediaPlayer())
     return 0;
-  // TODO(dtapuska): https://crbug.com/887593 Should the IDL change to be a
-  // unsigned long long?
-  return static_cast<unsigned>(GetWebMediaPlayer()->AudioDecodedByteCount());
+  return GetWebMediaPlayer()->AudioDecodedByteCount();
 }
 
-unsigned HTMLMediaElement::webkitVideoDecodedByteCount() const {
+uint64_t HTMLMediaElement::webkitVideoDecodedByteCount() const {
   if (!GetWebMediaPlayer())
     return 0;
-  // TODO(dtapuska): https://crbug.com/887593 Should the IDL change to be a
-  // unsigned long long?
-  return static_cast<unsigned>(GetWebMediaPlayer()->VideoDecodedByteCount());
+  return GetWebMediaPlayer()->VideoDecodedByteCount();
 }
 
 bool HTMLMediaElement::IsURLAttribute(const Attribute& attribute) const {
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.h b/third_party/blink/renderer/core/html/media/html_media_element.h
index bb753a53..5bd47e1d 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.h
+++ b/third_party/blink/renderer/core/html/media/html_media_element.h
@@ -204,8 +204,8 @@
   void FlingingStopped();
 
   // statistics
-  unsigned webkitAudioDecodedByteCount() const;
-  unsigned webkitVideoDecodedByteCount() const;
+  uint64_t webkitAudioDecodedByteCount() const;
+  uint64_t webkitVideoDecodedByteCount() const;
 
   // media source extensions
   void CloseMediaSource();
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.idl b/third_party/blink/renderer/core/html/media/html_media_element.idl
index 61972ef..3fa256d76 100644
--- a/third_party/blink/renderer/core/html/media/html_media_element.idl
+++ b/third_party/blink/renderer/core/html/media/html_media_element.idl
@@ -92,6 +92,6 @@
 
     // Non-standard APIs
     // The number of bytes consumed by the media decoder.
-    [MeasureAs=PrefixedAudioDecodedByteCount] readonly attribute unsigned long webkitAudioDecodedByteCount;
-    [MeasureAs=PrefixedVideoDecodedByteCount] readonly attribute unsigned long webkitVideoDecodedByteCount;
+    [MeasureAs=PrefixedAudioDecodedByteCount] readonly attribute unsigned long long webkitAudioDecodedByteCount;
+    [MeasureAs=PrefixedVideoDecodedByteCount] readonly attribute unsigned long long webkitVideoDecodedByteCount;
 };
diff --git a/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc b/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
index 0bf662c..d79dddb 100644
--- a/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
+++ b/third_party/blink/renderer/core/html/media/media_element_parser_helpers.cc
@@ -29,8 +29,10 @@
 }
 
 bool IsUnsizedMediaEnabled(const Document& document) {
-  if (auto* frame = document.GetFrame())
-    return frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kUnsizedMedia);
+  if (auto* frame = document.GetFrame()) {
+    return frame->DeprecatedIsFeatureEnabled(
+        mojom::FeaturePolicyFeature::kUnsizedMedia);
+  }
   // Unsized media is by default enabled every where, so when the frame is not
   // available return default policy (true).
   return true;
@@ -75,7 +77,7 @@
   const ComputedStyle& style = layout_object->StyleRef();
   if (!style.LogicalWidth().IsSpecified() &&
       !style.LogicalHeight().IsSpecified() && layout_object->GetFrame()) {
-    layout_object->GetFrame()->ReportFeaturePolicyViolation(
+    layout_object->GetFrame()->DeprecatedReportFeaturePolicyViolation(
         mojom::FeaturePolicyFeature::kUnsizedMedia);
   }
 }
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
index 2627856..29fbfa1 100644
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_test.cc
@@ -312,47 +312,6 @@
   }
 }
 
-enum class ColorSpaceConversion : uint8_t {
-  NONE = 0,
-  DEFAULT_COLOR_CORRECTED = 1,
-  PRESERVE = 2,
-  SRGB = 3,
-  LINEAR_RGB = 4,
-  P3 = 5,
-  REC2020 = 6,
-
-  LAST = REC2020
-};
-
-static ImageBitmapOptions PrepareBitmapOptions(
-    const ColorSpaceConversion& color_space_conversion) {
-  // Set the color space conversion in ImageBitmapOptions
-  ImageBitmapOptions options;
-  static const Vector<String> kConversions = {
-      "none", "default", "preserve", "srgb", "linear-rgb", "p3", "rec2020"};
-  options.setColorSpaceConversion(
-      kConversions[static_cast<uint8_t>(color_space_conversion)]);
-  return options;
-}
-
-static sk_sp<SkColorSpace> GetColorSpaceForColorSpaceConversion(
-    ColorSpaceConversion conversion) {
-  sk_sp<SkColorSpace> color_space = nullptr;
-  if (conversion == ColorSpaceConversion::DEFAULT_COLOR_CORRECTED ||
-      conversion == ColorSpaceConversion::SRGB) {
-    color_space = SkColorSpace::MakeSRGB();
-  } else if (conversion == ColorSpaceConversion::LINEAR_RGB) {
-    color_space = SkColorSpace::MakeSRGBLinear();
-  } else if (conversion == ColorSpaceConversion::P3) {
-    color_space = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
-                                        SkColorSpace::kDCIP3_D65_Gamut);
-  } else if (conversion == ColorSpaceConversion::REC2020) {
-    color_space = SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
-                                        SkColorSpace::kRec2020_Gamut);
-  }
-  return color_space;
-}
-
 TEST_F(ImageBitmapTest, ImageBitmapColorSpaceConversionHTMLImageElement) {
   HTMLImageElement* image_element =
       HTMLImageElement::Create(*Document::CreateForTest());
@@ -377,13 +336,13 @@
   base::Optional<IntRect> crop_rect =
       IntRect(0, 0, source_image->width(), source_image->height());
 
-  for (uint8_t i =
-           static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED);
-       i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) {
-    ColorSpaceConversion color_space_conversion =
-        static_cast<ColorSpaceConversion>(i);
-    ImageBitmapOptions options =
-        PrepareBitmapOptions(color_space_conversion);
+  for (int conversion_iterator = kColorSpaceConversion_Default;
+       conversion_iterator <= kColorSpaceConversion_Last;
+       conversion_iterator++) {
+    ImageBitmapOptions options;
+    options.setColorSpaceConversion(
+        ColorCorrectionTestUtils::ColorSpaceConversionToString(
+            static_cast<ColorSpaceConversion>(conversion_iterator)));
     ImageBitmap* image_bitmap = ImageBitmap::Create(
         image_element, crop_rect, &(image_element->GetDocument()), options);
     ASSERT_TRUE(image_bitmap);
@@ -393,7 +352,7 @@
     converted_image->peekPixels(&converted_pixmap);
     unsigned num_pixels = source_image->width() * source_image->height();
 
-    if (color_space_conversion == ColorSpaceConversion::PRESERVE) {
+    if (conversion_iterator == kColorSpaceConversion_Preserve) {
       EXPECT_TRUE(
           SkColorSpace::Equals(colorspin.get(), converted_image->colorSpace()));
       ColorCorrectionTestUtils::CompareColorCorrectedPixels(
@@ -401,7 +360,8 @@
           kPixelFormat_8888, kAlphaMultiplied, kUnpremulRoundTripTolerance);
     } else {
       sk_sp<SkColorSpace> color_space =
-          GetColorSpaceForColorSpaceConversion(color_space_conversion);
+          ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace(
+              static_cast<ColorSpaceConversion>(conversion_iterator));
       EXPECT_TRUE(SkColorSpace::Equals(color_space.get(),
                                        converted_image->colorSpace()));
 
@@ -412,8 +372,7 @@
             expected_image_info.makeColorType(kRGBA_F16_SkColorType);
       }
       SkBitmap expected_bitmap;
-      EXPECT_TRUE(expected_bitmap.tryAllocPixels(
-          expected_image_info, expected_image_info.minRowBytes()));
+      EXPECT_TRUE(expected_bitmap.tryAllocPixels(expected_image_info));
       source_image->readPixels(expected_bitmap.pixmap(), 0, 0);
 
       ColorCorrectionTestUtils::CompareColorCorrectedPixels(
@@ -439,18 +398,20 @@
 
   base::Optional<IntRect> crop_rect =
       IntRect(0, 0, source_image->width(), source_image->height());
-  ImageBitmapOptions options =
-      PrepareBitmapOptions(ColorSpaceConversion::PRESERVE);
+  ImageBitmapOptions options;
+  options.setColorSpaceConversion(
+      ColorCorrectionTestUtils::ColorSpaceConversionToString(
+          kColorSpaceConversion_Preserve));
   ImageBitmap* source_image_bitmap = ImageBitmap::Create(
       StaticBitmapImage::Create(source_image), crop_rect, options);
   ASSERT_TRUE(source_image_bitmap);
 
-  for (uint8_t i =
-           static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED);
-       i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) {
-    ColorSpaceConversion color_space_conversion =
-        static_cast<ColorSpaceConversion>(i);
-    options = PrepareBitmapOptions(color_space_conversion);
+  for (int conversion_iterator = kColorSpaceConversion_Default;
+       conversion_iterator <= kColorSpaceConversion_Last;
+       conversion_iterator++) {
+    options.setColorSpaceConversion(
+        ColorCorrectionTestUtils::ColorSpaceConversionToString(
+            static_cast<ColorSpaceConversion>(conversion_iterator)));
     ImageBitmap* image_bitmap =
         ImageBitmap::Create(source_image_bitmap, crop_rect, options);
     ASSERT_TRUE(image_bitmap);
@@ -460,7 +421,7 @@
     converted_image->peekPixels(&converted_pixmap);
     unsigned num_pixels = source_image->width() * source_image->height();
 
-    if (color_space_conversion == ColorSpaceConversion::PRESERVE) {
+    if (conversion_iterator == kColorSpaceConversion_Preserve) {
       EXPECT_TRUE(
           SkColorSpace::Equals(colorspin.get(), converted_image->colorSpace()));
       ColorCorrectionTestUtils::CompareColorCorrectedPixels(
@@ -468,7 +429,8 @@
           kPixelFormat_8888, kAlphaMultiplied, kUnpremulRoundTripTolerance);
     } else {
       sk_sp<SkColorSpace> color_space =
-          GetColorSpaceForColorSpaceConversion(color_space_conversion);
+          ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace(
+              static_cast<ColorSpaceConversion>(conversion_iterator));
       EXPECT_TRUE(SkColorSpace::Equals(color_space.get(),
                                        converted_image->colorSpace()));
 
@@ -479,8 +441,7 @@
             expected_image_info.makeColorType(kRGBA_F16_SkColorType);
       }
       SkBitmap expected_bitmap;
-      EXPECT_TRUE(expected_bitmap.tryAllocPixels(
-          expected_image_info, expected_image_info.minRowBytes()));
+      EXPECT_TRUE(expected_bitmap.tryAllocPixels(expected_image_info));
       source_image->readPixels(expected_bitmap.pixmap(), 0, 0);
 
       ColorCorrectionTestUtils::CompareColorCorrectedPixels(
@@ -507,13 +468,13 @@
   base::Optional<IntRect> crop_rect =
       IntRect(0, 0, source_image->width(), source_image->height());
 
-  for (uint8_t i =
-           static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED);
-       i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) {
-    ColorSpaceConversion color_space_conversion =
-        static_cast<ColorSpaceConversion>(i);
-    ImageBitmapOptions options =
-        PrepareBitmapOptions(color_space_conversion);
+  for (int conversion_iterator = kColorSpaceConversion_Default;
+       conversion_iterator <= kColorSpaceConversion_Last;
+       conversion_iterator++) {
+    ImageBitmapOptions options;
+    options.setColorSpaceConversion(
+        ColorCorrectionTestUtils::ColorSpaceConversionToString(
+            static_cast<ColorSpaceConversion>(conversion_iterator)));
     ImageBitmap* image_bitmap = ImageBitmap::Create(
         StaticBitmapImage::Create(source_image), crop_rect, options);
     ASSERT_TRUE(image_bitmap);
@@ -523,7 +484,7 @@
     converted_image->peekPixels(&converted_pixmap);
     unsigned num_pixels = source_image->width() * source_image->height();
 
-    if (color_space_conversion == ColorSpaceConversion::PRESERVE) {
+    if (conversion_iterator == kColorSpaceConversion_Preserve) {
       EXPECT_TRUE(
           SkColorSpace::Equals(colorspin.get(), converted_image->colorSpace()));
       ColorCorrectionTestUtils::CompareColorCorrectedPixels(
@@ -531,7 +492,8 @@
           kPixelFormat_8888, kAlphaMultiplied, kUnpremulRoundTripTolerance);
     } else {
       sk_sp<SkColorSpace> color_space =
-          GetColorSpaceForColorSpaceConversion(color_space_conversion);
+          ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace(
+              static_cast<ColorSpaceConversion>(conversion_iterator));
       EXPECT_TRUE(SkColorSpace::Equals(color_space.get(),
                                        converted_image->colorSpace()));
 
@@ -542,8 +504,7 @@
             expected_image_info.makeColorType(kRGBA_F16_SkColorType);
       }
       SkBitmap expected_bitmap;
-      EXPECT_TRUE(expected_bitmap.tryAllocPixels(
-          expected_image_info, expected_image_info.minRowBytes()));
+      EXPECT_TRUE(expected_bitmap.tryAllocPixels(expected_image_info));
       source_image->readPixels(expected_bitmap.pixmap(), 0, 0);
 
       ColorCorrectionTestUtils::CompareColorCorrectedPixels(
@@ -565,21 +526,20 @@
       SkImageInfo::Make(1, 1, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType,
                         SkColorSpace::MakeSRGB());
   SkBitmap source_bitmap;
-  EXPECT_TRUE(
-      source_bitmap.tryAllocPixels(image_info, image_info.minRowBytes()));
+  EXPECT_TRUE(source_bitmap.tryAllocPixels(image_info));
   SkPixmap source_pixmap;
   source_pixmap = source_bitmap.pixmap();
   memcpy(source_pixmap.writable_addr(), image_data->BufferBase()->Data(), 4);
 
   base::Optional<IntRect> crop_rect = IntRect(0, 0, 1, 1);
 
-  for (uint8_t i =
-           static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED);
-       i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) {
-    ColorSpaceConversion color_space_conversion =
-        static_cast<ColorSpaceConversion>(i);
-    ImageBitmapOptions options =
-        PrepareBitmapOptions(color_space_conversion);
+  for (int conversion_iterator = kColorSpaceConversion_Default;
+       conversion_iterator <= kColorSpaceConversion_Last;
+       conversion_iterator++) {
+    ImageBitmapOptions options;
+    options.setColorSpaceConversion(
+        ColorCorrectionTestUtils::ColorSpaceConversionToString(
+            static_cast<ColorSpaceConversion>(conversion_iterator)));
     ImageBitmap* image_bitmap =
         ImageBitmap::Create(image_data, crop_rect, options);
     ASSERT_TRUE(image_bitmap);
@@ -589,13 +549,12 @@
     converted_image->peekPixels(&converted_pixmap);
     unsigned num_pixels = converted_image->width() * converted_image->height();
 
-    if (color_space_conversion == ColorSpaceConversion::PRESERVE) {
+    if (conversion_iterator == kColorSpaceConversion_Preserve) {
       // crbug.com/886999
       // EXPECT_TRUE(SkColorSpace::Equals(SkColorSpace::MakeSRGB().get(),
       //                                  converted_image->colorSpace()));
       SkBitmap expected_bitmap;
-      EXPECT_TRUE(expected_bitmap.tryAllocPixels(
-          converted_pixmap.info(), converted_pixmap.info().minRowBytes()));
+      EXPECT_TRUE(expected_bitmap.tryAllocPixels(converted_pixmap.info()));
       source_pixmap.readPixels(expected_bitmap.pixmap(), 0, 0);
 
       ColorCorrectionTestUtils::CompareColorCorrectedPixels(
@@ -603,13 +562,13 @@
           kPixelFormat_8888, kAlphaMultiplied, kUnpremulRoundTripTolerance);
     } else {
       sk_sp<SkColorSpace> color_space =
-          GetColorSpaceForColorSpaceConversion(color_space_conversion);
+          ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace(
+              static_cast<ColorSpaceConversion>(conversion_iterator));
       // crbug.com/886999
       // EXPECT_TRUE(SkColorSpace::Equals(color_space.get(),
       //                                  converted_image->colorSpace()));
       SkBitmap expected_bitmap;
-      EXPECT_TRUE(expected_bitmap.tryAllocPixels(
-          converted_pixmap.info(), converted_pixmap.info().minRowBytes()));
+      EXPECT_TRUE(expected_bitmap.tryAllocPixels(converted_pixmap.info()));
       source_pixmap.readPixels(expected_bitmap.pixmap(), 0, 0);
 
       ColorCorrectionTestUtils::CompareColorCorrectedPixels(
@@ -699,12 +658,13 @@
   ImageData* image_data =
       ImageData::CreateForTest(IntSize(v8::TypedArray::kMaxLength / 16, 1));
   DCHECK(image_data);
-  ImageBitmapOptions options =
-      PrepareBitmapOptions(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED);
+  ImageBitmapOptions options;
+  options.setColorSpaceConversion(
+      ColorCorrectionTestUtils::ColorSpaceConversionToString(
+          kColorSpaceConversion_Default));
   ImageBitmap* image_bitmap = ImageBitmap::Create(
       image_data, IntRect(IntPoint(0, 0), image_data->Size()), options);
   DCHECK(image_bitmap);
 }
 
-#undef MAYBE_ImageBitmapColorSpaceConversionHTMLImageElement
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/BUILD.gn b/third_party/blink/renderer/core/layout/BUILD.gn
index cdd86e7..c3229c1 100644
--- a/third_party/blink/renderer/core/layout/BUILD.gn
+++ b/third_party/blink/renderer/core/layout/BUILD.gn
@@ -377,6 +377,8 @@
     "ng/inline/ng_text_fragment_builder.h",
     "ng/layout_ng_block_flow.cc",
     "ng/layout_ng_block_flow.h",
+    "ng/layout_ng_fieldset.cc",
+    "ng/layout_ng_fieldset.h",
     "ng/layout_ng_flexible_box.cc",
     "ng/layout_ng_flexible_box.h",
     "ng/layout_ng_mixin.cc",
@@ -419,6 +421,8 @@
     "ng/ng_constraint_space_builder.h",
     "ng/ng_container_fragment_builder.cc",
     "ng/ng_container_fragment_builder.h",
+    "ng/ng_fieldset_layout_algorithm.cc",
+    "ng/ng_fieldset_layout_algorithm.h",
     "ng/ng_flex_layout_algorithm.cc",
     "ng/ng_flex_layout_algorithm.h",
     "ng/ng_floats_utils.cc",
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index 3322348e5..a978ab44 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -5204,16 +5204,6 @@
   return ToLayoutCustom(Parent())->Phase() == LayoutCustomPhase::kCustom;
 }
 
-bool LayoutBox::IsRenderedLegend() const {
-  if (!IsHTMLLegendElement(GetNode()))
-    return false;
-  if (IsFloatingOrOutOfFlowPositioned())
-    return false;
-  const auto* parent = Parent();
-  return parent && parent->IsFieldset() &&
-         ToLayoutFieldset(parent)->FindInFlowLegend() == this;
-}
-
 void LayoutBox::AddVisualEffectOverflow() {
   if (!StyleRef().HasVisualOverflowingEffect())
     return;
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 41ac33b..7c3658c 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1213,11 +1213,6 @@
 
   bool IsGridItem() const { return Parent() && Parent()->IsLayoutGrid(); }
 
-  // Return true if this is the "rendered legend" of a fieldset. They get
-  // special treatment, in that they establish a new formatting context, and
-  // shrink to fit if no logical width is specified.
-  bool IsRenderedLegend() const;
-
   LayoutUnit LineHeight(
       bool first_line,
       LineDirectionMode,
diff --git a/third_party/blink/renderer/core/layout/layout_fieldset.cc b/third_party/blink/renderer/core/layout/layout_fieldset.cc
index 2d661fb..d4089429 100644
--- a/third_party/blink/renderer/core/layout/layout_fieldset.cc
+++ b/third_party/blink/renderer/core/layout/layout_fieldset.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/html/forms/html_legend_element.h"
 #include "third_party/blink/renderer/core/html_names.h"
 #include "third_party/blink/renderer/core/paint/fieldset_painter.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 
 namespace blink {
 
@@ -136,8 +137,19 @@
   return legend;
 }
 
-LayoutBox* LayoutFieldset::FindInFlowLegend() const {
-  for (LayoutObject* legend = FirstChild(); legend;
+LayoutBox* LayoutFieldset::FindInFlowLegend(const LayoutBlock& fieldset) {
+  DCHECK(fieldset.IsFieldset() || fieldset.IsLayoutNGFieldset());
+  const LayoutBlock* parent = &fieldset;
+  if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled()) {
+    if (fieldset.IsLayoutNGFieldset()) {
+      // If there is a rendered legend, it will be found inside the anonymous
+      // fieldset wrapper.
+      parent = ToLayoutBlock(fieldset.FirstChild());
+      if (!parent)
+        return nullptr;
+    }
+  }
+  for (LayoutObject* legend = parent->FirstChild(); legend;
        legend = legend->NextSibling()) {
     if (legend->IsFloatingOrOutOfFlowPositioned())
       continue;
diff --git a/third_party/blink/renderer/core/layout/layout_fieldset.h b/third_party/blink/renderer/core/layout/layout_fieldset.h
index 4d38cd0..f0218778 100644
--- a/third_party/blink/renderer/core/layout/layout_fieldset.h
+++ b/third_party/blink/renderer/core/layout/layout_fieldset.h
@@ -32,7 +32,8 @@
  public:
   explicit LayoutFieldset(Element*);
 
-  LayoutBox* FindInFlowLegend() const;
+  static LayoutBox* FindInFlowLegend(const LayoutBlock& fieldset);
+  LayoutBox* FindInFlowLegend() const { return FindInFlowLegend(*this); }
 
   const char* GetName() const override { return "LayoutFieldset"; }
 
diff --git a/third_party/blink/renderer/core/layout/layout_image.cc b/third_party/blink/renderer/core/layout/layout_image.cc
index a74fcf6..710f7f9 100644
--- a/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/third_party/blink/renderer/core/layout/layout_image.cc
@@ -58,7 +58,7 @@
   // Invert the image if the document does not have the 'legacy-image-formats'
   // feature enabled, and the image is not one of the allowed formats.
   if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
-      !frame.IsFeatureEnabled(
+      !frame.DeprecatedIsFeatureEnabled(
           mojom::FeaturePolicyFeature::kLegacyImageFormats)) {
     if (!new_image->IsAcceptableContentType()) {
       return true;
@@ -67,7 +67,8 @@
   // Invert the image if the document does not have the image-compression'
   // feature enabled and the image is not sufficiently-well-compressed.
   if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
-      !frame.IsFeatureEnabled(mojom::FeaturePolicyFeature::kImageCompression)) {
+      !frame.DeprecatedIsFeatureEnabled(
+          mojom::FeaturePolicyFeature::kImageCompression)) {
     if (!new_image->IsAcceptableCompressionRatio())
       return true;
   }
@@ -79,7 +80,8 @@
                                        LayoutImage* layout_image) {
   DCHECK(new_image);
   if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() ||
-      frame.IsFeatureEnabled(mojom::FeaturePolicyFeature::kMaxDownscalingImage))
+      frame.DeprecatedIsFeatureEnabled(
+          mojom::FeaturePolicyFeature::kMaxDownscalingImage))
     return false;
   if (auto* image = new_image->GetImage()) {
     // Invert the image if the image's size is more than 2 times bigger than the
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc
index 8df9cbb2..f3bff39 100644
--- a/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -63,6 +63,7 @@
 #include "third_party/blink/renderer/core/layout/layout_counter.h"
 #include "third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
+#include "third_party/blink/renderer/core/layout/layout_fieldset.h"
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/layout_flow_thread.h"
 #include "third_party/blink/renderer/core/layout/layout_grid.h"
@@ -485,6 +486,23 @@
   return false;
 }
 
+bool LayoutObject::IsRenderedLegend() const {
+  if (!IsBox() || !IsHTMLLegendElement(GetNode()))
+    return false;
+  if (IsFloatingOrOutOfFlowPositioned())
+    return false;
+  const auto* parent = Parent();
+  if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled()) {
+    // If there is a rendered legend, it will be found inside the anonymous
+    // fieldset wrapper.
+    if (parent->IsAnonymous() && parent->Parent()->IsLayoutNGFieldset())
+      parent = parent->Parent();
+  }
+  return parent && parent->IsLayoutBlock() &&
+         IsHTMLFieldSetElement(parent->GetNode()) &&
+         LayoutFieldset::FindInFlowLegend(*ToLayoutBlock(parent)) == this;
+}
+
 LayoutObject* LayoutObject::NextInPreOrderAfterChildren() const {
   LayoutObject* o = NextSibling();
   if (!o) {
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h
index e1eab26..0e7bece 100644
--- a/third_party/blink/renderer/core/layout/layout_object.h
+++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -554,6 +554,7 @@
     return IsOfType(kLayoutObjectEmbeddedObject);
   }
   bool IsFieldset() const { return IsOfType(kLayoutObjectFieldset); }
+  bool IsLayoutNGFieldset() const { return IsOfType(kLayoutObjectNGFieldset); }
   bool IsFileUploadControl() const {
     return IsOfType(kLayoutObjectFileUploadControl);
   }
@@ -949,6 +950,11 @@
     return bitfields_.IsEffectiveRootScroller();
   }
 
+  // Return true if this is the "rendered legend" of a fieldset. They get
+  // special treatment, in that they establish a new formatting context, and
+  // shrink to fit if no logical width is specified.
+  bool IsRenderedLegend() const;
+
   // The pseudo element style can be cached or uncached.  Use the cached method
   // if the pseudo element doesn't respect any pseudo classes (and therefore
   // has no concept of changing state).
@@ -2108,6 +2114,7 @@
     kLayoutObjectMedia,
     kLayoutObjectMenuList,
     kLayoutObjectNGBlockFlow,
+    kLayoutObjectNGFieldset,
     kLayoutObjectNGFlexibleBox,
     kLayoutObjectNGMixin,
     kLayoutObjectNGListItem,
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.cc b/third_party/blink/renderer/core/layout/layout_object_factory.cc
index 2450739..064ed12 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.cc
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -6,12 +6,14 @@
 
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/layout_fieldset.h"
 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/layout_list_item.h"
 #include "third_party/blink/renderer/core/layout/layout_table_caption.h"
 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
 #include "third_party/blink/renderer/core/layout/layout_view.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h"
 #include "third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h"
@@ -92,4 +94,14 @@
   return new LayoutTableCell(element);
 }
 
+LayoutBlock* LayoutObjectFactory::CreateFieldset(Node& node,
+                                                 const ComputedStyle& style) {
+  Element* element = GetElementForLayoutObject(node);
+  if (RuntimeEnabledFeatures::LayoutNGFieldsetEnabled() &&
+      ShouldUseNewLayout(node.GetDocument(), style)) {
+    return new LayoutNGFieldset(element);
+  }
+  return new LayoutFieldset(element);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_object_factory.h b/third_party/blink/renderer/core/layout/layout_object_factory.h
index 5e99c9a..0a22e84 100644
--- a/third_party/blink/renderer/core/layout/layout_object_factory.h
+++ b/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -5,15 +5,16 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_OBJECT_FACTORY_H_
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_OBJECT_FACTORY_H_
 
-#include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 
 namespace blink {
 
+class ComputedStyle;
 class LayoutBlock;
 class LayoutBlockFlow;
 class LayoutTableCaption;
 class LayoutTableCell;
+class Node;
 
 // Helper class for creation of certain LayoutObject-derived objects that may
 // need to be of different types, depending on whether or not LayoutNG is to be
@@ -32,6 +33,7 @@
   static LayoutBlockFlow* CreateListItem(Node&, const ComputedStyle&);
   static LayoutTableCaption* CreateTableCaption(Node&, const ComputedStyle&);
   static LayoutTableCell* CreateTableCell(Node&, const ComputedStyle&);
+  static LayoutBlock* CreateFieldset(Node&, const ComputedStyle&);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index f90bd1a..0f40644 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -743,27 +743,24 @@
   Vector<NGPositionedFloat> positioned_floats;
   NGUnpositionedFloatVector unpositioned_floats;
 
-  scoped_refptr<NGInlineBreakToken> break_token;
   NGExclusionSpace empty_exclusion_space;
   NGLineLayoutOpportunity line_opportunity(available_inline_size);
   LayoutUnit result;
   LayoutUnit previous_floats_inline_size =
       input.float_left_inline_size + input.float_right_inline_size;
   DCHECK_GE(previous_floats_inline_size, 0);
-  while (!break_token || !break_token->IsFinished()) {
+  NGLineBreaker line_breaker(
+      node, mode, space, &positioned_floats, &unpositioned_floats,
+      nullptr /* container_builder */, &empty_exclusion_space, 0u,
+      line_opportunity, nullptr /* break_token */);
+  do {
     unpositioned_floats.clear();
 
     NGLineInfo line_info;
-    NGLineBreaker line_breaker(
-        node, mode, space, &positioned_floats, &unpositioned_floats,
-        nullptr /* container_builder */, &empty_exclusion_space, 0u,
-        line_opportunity, break_token.get());
     line_breaker.NextLine(&line_info);
-
     if (line_info.Results().IsEmpty())
       break;
 
-    break_token = line_breaker.CreateBreakToken(line_info, nullptr);
     LayoutUnit inline_size = line_info.Width();
     DCHECK_EQ(inline_size, line_info.ComputeWidth().ClampNegativeToZero());
 
@@ -829,7 +826,7 @@
     // NOTE: floats_inline_size will be zero for the min-content calculation,
     // and will just take the inline size of the un-breakable line.
     result = std::max(result, inline_size + floats_inline_size);
-  }
+  } while (!line_breaker.IsFinished());
 
   return result;
 }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index 4f5c87e..9d1e8d81 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -81,7 +81,7 @@
     item_index_ = break_token->ItemIndex();
     offset_ = break_token->TextOffset();
     break_iterator_.SetStartOffset(offset_);
-    previous_line_had_forced_break_ = break_token->IsForcedBreak();
+    is_after_forced_break_ = break_token->IsForcedBreak();
     items_data_.AssertOffset(item_index_, offset_);
     ignore_floats_ = break_token->IgnoreFloats();
   }
@@ -147,6 +147,14 @@
   // avoid rare code path.
   DCHECK(item_results_->IsEmpty());
 
+  if (item_index_) {
+    // We're past the first line
+    previous_line_had_forced_break_ = is_after_forced_break_;
+    is_after_forced_break_ = false;
+    is_first_formatted_line_ = false;
+    use_first_line_style_ = false;
+  }
+
   line_info_->SetStartOffset(offset_);
   line_info_->SetLineStyle(node_, items_data_, constraint_space_,
                            is_first_formatted_line_, use_first_line_style_,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
index 238da9b..8961787 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -51,6 +51,8 @@
   // the line.
   void NextLine(NGLineInfo*);
 
+  bool IsFinished() const { return item_index_ >= Items().size(); }
+
   // Create an NGInlineBreakToken for the last line returned by NextLine().
   scoped_refptr<NGInlineBreakToken> CreateBreakToken(
       const NGLineInfo&,
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
new file mode 100644
index 0000000..862f6ad
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
@@ -0,0 +1,80 @@
+// 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 "third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h"
+
+#include "third_party/blink/renderer/core/layout/layout_object_factory.h"
+
+namespace blink {
+
+LayoutNGFieldset::LayoutNGFieldset(Element* element)
+    : LayoutNGBlockFlow(element) {
+  SetChildrenInline(false);
+}
+
+void LayoutNGFieldset::AddChild(LayoutObject* new_child,
+                                LayoutObject* before_child) {
+  LayoutBlock* fieldset_content = ToLayoutBlock(FirstChild());
+  if (!fieldset_content) {
+    // We wrap everything inside an anonymous child, which will take care of the
+    // fieldset contents. This parent will only be responsible for the fieldset
+    // border and the rendered legend, if there is one. Everything else will be
+    // done by the anonymous child. This includes display type, multicol,
+    // scrollbars, and even padding. Note that the rendered legend (if any) will
+    // also be a child of the anonymous object, although it'd be more natural to
+    // have it as the first child of this object. The reason is that our layout
+    // object tree builder cannot handle such discrepancies between DOM tree and
+    // layout tree. Inserting anonymous wrappers is one thing (that is
+    // supported). Removing it from its actual DOM siblings and putting it
+    // elsewhere, on the other hand, does not work well.
+
+    scoped_refptr<ComputedStyle> new_style =
+        ComputedStyle::CreateAnonymousStyleWithDisplay(StyleRef(),
+                                                       EDisplay::kFlowRoot);
+    new_style->SetOverflowX(StyleRef().OverflowX());
+    new_style->SetOverflowY(StyleRef().OverflowY());
+
+    new_style->SetPaddingTop(StyleRef().PaddingTop());
+    new_style->SetPaddingRight(StyleRef().PaddingRight());
+    new_style->SetPaddingBottom(StyleRef().PaddingBottom());
+    new_style->SetPaddingLeft(StyleRef().PaddingLeft());
+
+    if (StyleRef().SpecifiesColumns()) {
+      new_style->SetColumnCount(StyleRef().ColumnCount());
+      new_style->SetColumnWidth(StyleRef().ColumnWidth());
+    } else {
+      new_style->SetHasAutoColumnCount();
+      new_style->SetHasAutoColumnWidth();
+    }
+    new_style->SetColumnGap(StyleRef().ColumnGap());
+    new_style->SetColumnFill(StyleRef().GetColumnFill());
+
+    new_style->SetFlexDirection(StyleRef().FlexDirection());
+    new_style->SetJustifyContent(StyleRef().JustifyContent());
+
+    // TODO(mstensho): Inherit all properties listed here:
+    // https://html.spec.whatwg.org/multipage/rendering.html#the-fieldset-and-legend-elements
+
+    // We need to enter legacy layout from this point on, if ...
+    if (!RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled() &&
+        new_style->SpecifiesColumns())
+      new_style->SetForceLegacyLayout(true);
+
+    fieldset_content = LayoutBlock::CreateAnonymousWithParentAndDisplay(
+        this, new_style->Display());
+    fieldset_content->SetStyle(std::move(new_style));
+    LayoutBox::AddChild(fieldset_content);
+  }
+  fieldset_content->AddChild(new_child, before_child);
+}
+
+// TODO(mstensho): Should probably remove the anonymous child if it becomes
+// childless. While an empty anonymous child should have no effect, it doesn't
+// seem right to leave it around.
+
+bool LayoutNGFieldset::IsOfType(LayoutObjectType type) const {
+  return type == kLayoutObjectNGFieldset || LayoutNGBlockFlow::IsOfType(type);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h
new file mode 100644
index 0000000..e549fc8
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h
@@ -0,0 +1,30 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FIELDSET_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FIELDSET_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
+
+namespace blink {
+
+class CORE_EXPORT LayoutNGFieldset final : public LayoutNGBlockFlow {
+ public:
+  explicit LayoutNGFieldset(Element*);
+
+  const char* GetName() const override { return "LayoutNGFieldset"; }
+
+  void AddChild(LayoutObject* new_child,
+                LayoutObject* before_child = nullptr) override;
+
+ protected:
+  bool IsOfType(LayoutObjectType) const override;
+};
+
+DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGFieldset, IsLayoutNGFieldset());
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FIELDSET_H_
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index 176a4413..a9a72e99 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -249,19 +249,20 @@
 
 template <typename Base>
 void LayoutNGMixin<Base>::SetPaintFragment(
-    NGPaintFragment* last_paint_fragment,
-    scoped_refptr<NGPaintFragment> paint_fragment) {
-  if (paint_fragment) {
+    scoped_refptr<const NGPhysicalFragment> fragment,
+    NGPhysicalOffset offset,
+    scoped_refptr<NGPaintFragment>* current) {
+  DCHECK(current);
+
+  if (fragment) {
     // When paint fragment is replaced, the subtree needs paint invalidation to
     // re-compute paint properties in NGPaintFragment.
     Base::SetSubtreeShouldDoFullPaintInvalidation();
   }
 
-  if (last_paint_fragment) {
-    last_paint_fragment->SetNext(std::move(paint_fragment));
-  } else {
-    paint_fragment_ = std::move(paint_fragment);
-  }
+  *current = fragment ? NGPaintFragment::Create(std::move(fragment), offset,
+                                                std::move(*current))
+                      : nullptr;
 }
 
 template <typename Base>
@@ -272,19 +273,9 @@
   // TODO(kojii): There are cases where the first call has break_token.
   // Investigate why and handle appropriately.
   // DCHECK(!break_token || paint_fragment_);
-  NGPaintFragment* last_paint_fragment = nullptr;
-  if (break_token && paint_fragment_) {
-    last_paint_fragment = paint_fragment_->Last(*break_token);
-    // TODO(kojii): Sometimes an unknown break_token is given. Need to
-    // investigate why, and handle appropriately. For now, just keep it to avoid
-    // crashes and use-after-free.
-    if (!last_paint_fragment)
-      last_paint_fragment = paint_fragment_->Last();
-    DCHECK(last_paint_fragment);
-  }
-  SetPaintFragment(
-      last_paint_fragment,
-      fragment ? NGPaintFragment::Create(fragment, offset) : nullptr);
+  scoped_refptr<NGPaintFragment>* current =
+      NGPaintFragment::Find(&paint_fragment_, break_token);
+  SetPaintFragment(std::move(fragment), offset, current);
 }
 
 template <typename Base>
@@ -296,29 +287,12 @@
   // TODO(kojii): There are cases where the first call has break_token.
   // Investigate why and handle appropriately.
   // DCHECK(!break_token || paint_fragment_);
-  NGPaintFragment* paint_fragment = nullptr;
-  NGPaintFragment* last_paint_fragment = nullptr;
-  if (!break_token) {
-    paint_fragment = paint_fragment_.get();
-  } else if (paint_fragment_) {
-    last_paint_fragment = paint_fragment_->Last(*break_token);
-    // TODO(kojii): Sometimes an unknown break_token is given. Need to
-    // investigate why, and handle appropriately. For now, just keep it to avoid
-    // crashes and use-after-free.
-    if (!last_paint_fragment)
-      last_paint_fragment = paint_fragment_->Last();
-    DCHECK(last_paint_fragment);
-    paint_fragment = last_paint_fragment->Next();
-  }
-
-  if (!paint_fragment) {
-    SetPaintFragment(
-        last_paint_fragment,
-        NGPaintFragment::Create(std::move(fragment), fragment_offset));
-    return;
-  }
-
-  paint_fragment->UpdatePhysicalFragmentFromCachedLayoutResult(fragment);
+  scoped_refptr<NGPaintFragment>* current =
+      NGPaintFragment::Find(&paint_fragment_, break_token);
+  DCHECK(current);
+  DCHECK(*current);
+  (*current)->UpdateFromCachedLayoutResult(std::move(fragment),
+                                           fragment_offset);
 }
 
 template <typename Base>
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
index bd059b88..3673e5c 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -88,8 +88,9 @@
 
  private:
   void AddScrollingOverflowFromChildren();
-  void SetPaintFragment(NGPaintFragment* last_paint_fragment,
-                        scoped_refptr<NGPaintFragment>);
+  void SetPaintFragment(scoped_refptr<const NGPhysicalFragment> fragment,
+                        NGPhysicalOffset offset,
+                        scoped_refptr<NGPaintFragment>* current);
 
  protected:
   void AddOutlineRects(Vector<LayoutRect>&,
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
index 04e53b0..12689da 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
@@ -6,8 +6,10 @@
 
 #include "third_party/blink/renderer/core/layout/layout_analyzer.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
 
@@ -16,6 +18,39 @@
 LayoutNGTableCaption::LayoutNGTableCaption(Element* element)
     : LayoutNGMixin<LayoutTableCaption>(element) {}
 
+void LayoutNGTableCaption::CalculateAndSetMargins(
+    const NGConstraintSpace& constraint_space,
+    const NGPhysicalFragment& physical_fragment) {
+  const ComputedStyle& containing_block_style = ContainingBlock()->StyleRef();
+
+  NGBoxFragment box_fragment(containing_block_style.GetWritingMode(),
+                             containing_block_style.Direction(),
+                             ToNGPhysicalBoxFragment(physical_fragment));
+
+  NGPhysicalBoxStrut physical_margins =
+      ComputePhysicalMargins(constraint_space, StyleRef());
+
+  NGBoxStrut logical_margins =
+      physical_margins.ConvertToLogical(containing_block_style.GetWritingMode(),
+                                        containing_block_style.Direction());
+
+  LayoutUnit caption_inline_size_in_cb_writing_mode = box_fragment.InlineSize();
+
+  LayoutUnit available_inline_size_in_cb_writing_mode =
+      constraint_space.AvailableSize()
+          .ConvertToPhysical(constraint_space.GetWritingMode())
+          .ConvertToLogical(containing_block_style.GetWritingMode())
+          .inline_size;
+
+  ResolveInlineMargins(StyleRef(), containing_block_style,
+                       available_inline_size_in_cb_writing_mode,
+                       caption_inline_size_in_cb_writing_mode,
+                       &logical_margins);
+  SetMargin(
+      logical_margins.ConvertToPhysical(containing_block_style.GetWritingMode(),
+                                        containing_block_style.Direction()));
+}
+
 void LayoutNGTableCaption::UpdateBlockLayout(bool relayout_children) {
   LayoutAnalyzer::BlockScope analyzer(*this);
 
@@ -27,6 +62,8 @@
   scoped_refptr<NGLayoutResult> result =
       NGBlockNode(this).Layout(constraint_space);
 
+  CalculateAndSetMargins(constraint_space, *result->PhysicalFragment());
+
   // Tell legacy layout there were abspos descendents we couldn't place. We know
   // we have to pass up to legacy here because this method is legacy's entry
   // point to LayoutNG. If our parent were LayoutNG, it wouldn't have called
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h
index cacadfd..1ea6e59 100644
--- a/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h
+++ b/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h
@@ -19,6 +19,10 @@
   void UpdateBlockLayout(bool relayout_children) override;
 
   const char* GetName() const override { return "LayoutNGTableCaption"; }
+
+ private:
+  void CalculateAndSetMargins(const NGConstraintSpace&,
+                              const NGPhysicalFragment&);
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc
index 88ccb44..bba0d68 100644
--- a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc
+++ b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc
@@ -20,6 +20,11 @@
     return nullptr;
   if (child->IsLayoutFlowThread())
     return ToLayoutBlockFlow(child)->FirstChild();
+  // The rendered legend is a child of the anonymous wrapper inside the fieldset
+  // container. If we find it, skip it. As far as NG is concerned, the rendered
+  // legend is a child of the fieldset container.
+  if (UNLIKELY(child->IsRenderedLegend()))
+    return child->NextSibling();
   return child;
 }
 
@@ -32,11 +37,30 @@
   LayoutObject* parent = object->Parent();
   if (!parent)
     return nullptr;
+
+  // The parent of the rendered legend is the fieldset container, as far as NG
+  // is concerned. Skip the anonymous wrapper in-between.
+  if (UNLIKELY(object->IsRenderedLegend()))
+    return parent->Parent();
+
   if (parent->IsLayoutFlowThread())
     return parent->Parent();
   return parent;
 }
 
+LayoutObject* GetLayoutObjectForNextSiblingNode(LayoutObject* object) {
+  // We don't expect to walk the layout tree starting at the rendered legend,
+  // and we'll skip over it if we find it. The renderered legend will be handled
+  // by a special algorithm, and should be invisible among siblings.
+  DCHECK(!object->IsRenderedLegend());
+  LayoutObject* next = object->NextSibling();
+  if (!next)
+    return nullptr;
+  if (UNLIKELY(next->IsRenderedLegend()))
+    return next->NextSibling();
+  return next;
+}
+
 bool AreNGBlockFlowChildrenInline(const LayoutBlock* block) {
   if (block->ChildrenInline())
     return true;
diff --git a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
index 79bf10c..bd52a27 100644
--- a/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
+++ b/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
@@ -20,6 +20,11 @@
 // are certain layout objects that should be skipped for NG.
 LayoutObject* GetLayoutObjectForParentNode(LayoutObject*);
 
+// Return the layout object that should be the sibling NGLayoutInputNode of
+// |object|. Normally this will just be the next sibling layout object, but
+// there are certain layout objects that should be skipped for NG.
+LayoutObject* GetLayoutObjectForNextSiblingNode(LayoutObject*);
+
 // Return true if the NGLayoutInputNode children of the NGLayoutInputNode
 // established by |block| will be inline; see LayoutObject::ChildrenInline().
 bool AreNGBlockFlowChildrenInline(const LayoutBlock*);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 8b8010a..f5c1a3d 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -9,6 +9,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/html/html_marquee_element.h"
 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/layout_fieldset.h"
 #include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
 #include "third_party/blink/renderer/core/layout/layout_multi_column_set.h"
 #include "third_party/blink/renderer/core/layout/min_max_size.h"
@@ -21,6 +22,7 @@
 #include "third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h"
 #include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
@@ -52,6 +54,8 @@
     const ComputedStyle& style = node.Style();                               \
     if (node.GetLayoutBox()->IsLayoutNGFlexibleBox())                        \
       return NGFlexLayoutAlgorithm(node, space, token).func args;            \
+    if (node.GetLayoutBox()->IsLayoutNGFieldset())                           \
+      return NGFieldsetLayoutAlgorithm(node, space, token).func args;        \
     /* If there's a legacy layout box, we can only do block fragmentation if \
      * we would have done block fragmentation with the legacy engine.        \
      * Otherwise writing data back into the legacy tree will fail. Look for  \
@@ -433,7 +437,7 @@
 }
 
 NGLayoutInputNode NGBlockNode::NextSibling() const {
-  LayoutObject* next_sibling = box_->NextSibling();
+  LayoutObject* next_sibling = GetLayoutObjectForNextSiblingNode(box_);
   if (next_sibling) {
     DCHECK(!next_sibling->IsInline());
     return NGBlockNode(ToLayoutBox(next_sibling));
@@ -451,6 +455,21 @@
   return NGBlockNode(ToLayoutBox(child));
 }
 
+NGBlockNode NGBlockNode::GetRenderedLegend() const {
+  if (!IsFieldsetContainer())
+    return nullptr;
+  return NGBlockNode(LayoutFieldset::FindInFlowLegend(*ToLayoutBlock(box_)));
+}
+
+NGBlockNode NGBlockNode::GetFieldsetContent() const {
+  if (!IsFieldsetContainer())
+    return nullptr;
+  auto* child = GetLayoutObjectForFirstChildNode(ToLayoutBlock(box_));
+  if (!child)
+    return nullptr;
+  return NGBlockNode(ToLayoutBox(child));
+}
+
 bool NGBlockNode::CanUseNewLayout(const LayoutBox& box) {
   DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
   if (box.StyleRef().ForceLegacyLayout())
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.h b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
index 74bb0ee..bf88b69 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_block_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.h
@@ -31,6 +31,8 @@
  public:
   explicit NGBlockNode(LayoutBox* box) : NGLayoutInputNode(box, kBlock) {}
 
+  NGBlockNode(std::nullptr_t) : NGLayoutInputNode(nullptr) {}
+
   scoped_refptr<NGLayoutResult> Layout(
       const NGConstraintSpace& constraint_space,
       NGBreakToken* break_token = nullptr);
@@ -64,6 +66,9 @@
 
   NGLayoutInputNode FirstChild() const;
 
+  NGBlockNode GetRenderedLegend() const;
+  NGBlockNode GetFieldsetContent() const;
+
   bool IsInlineLevel() const;
   bool IsAtomicInlineLevel() const;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
new file mode 100644
index 0000000..8c3010b
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
@@ -0,0 +1,171 @@
+// 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 "third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h"
+
+#include "third_party/blink/renderer/core/layout/layout_fieldset.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+
+namespace blink {
+
+NGFieldsetLayoutAlgorithm::NGFieldsetLayoutAlgorithm(
+    NGBlockNode node,
+    const NGConstraintSpace& space,
+    NGBreakToken* break_token)
+    : NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)) {}
+
+scoped_refptr<NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
+  // TODO(mstensho): Support block fragmentation.
+  DCHECK(!BreakToken());
+
+  // Layout of a fieldset container consists of two parts: Create a child
+  // fragment for the rendered legend (if any), and create a child fragment for
+  // the fieldset contents anonymous box (if any). Fieldset scrollbars and
+  // padding will not be applied to the fieldset container itself, but rather to
+  // the fieldset contents anonymous child box. The reason for this is that the
+  // rendered legend shouldn't be part of the scrollport; the legend is
+  // essentially a part of the block-start border, and should not scroll along
+  // with the actual fieldset contents. Since scrollbars are handled by the
+  // anonymous child box, and since padding is inside the scrollport, padding
+  // also needs to be handled by the anonymous child.
+  NGBoxStrut borders = ComputeBorders(ConstraintSpace(), Style());
+  NGBoxStrut padding = ComputePadding(ConstraintSpace(), Style());
+  NGLogicalSize border_box_size =
+      CalculateBorderBoxSize(ConstraintSpace(), Node());
+  const auto writing_mode = ConstraintSpace().GetWritingMode();
+  LayoutUnit block_start_padding_edge = borders.block_start;
+
+  if (NGBlockNode legend = Node().GetRenderedLegend()) {
+    // Lay out the legend. While the fieldset container normally ignores its
+    // padding, the legend is laid out within what would have been the content
+    // box had the fieldset been a regular block with no weirdness.
+    NGBoxStrut borders_padding = borders + padding;
+    NGLogicalSize content_box_size =
+        ShrinkAvailableSize(border_box_size, borders_padding);
+    auto legend_space =
+        CreateConstraintSpaceForLegend(legend, content_box_size);
+    auto result = legend.Layout(legend_space, BreakToken());
+    NGBoxStrut legend_margins =
+        ComputeMarginsFor(legend_space, legend.Style(), ConstraintSpace());
+    NGFragment logical_fragment(writing_mode, *result->PhysicalFragment());
+    // If the margin box of the legend is at least as tall as the fieldset
+    // block-start border width, it will start at the block-start border edge of
+    // the fieldset. As a paint effect, the block-start border will be pushed so
+    // that the center of the border will be flush with the center of the
+    // border-box of the legend.
+    // TODO(mstensho): inline alignment
+    NGLogicalOffset legend_offset = NGLogicalOffset(
+        borders_padding.inline_start + legend_margins.inline_start,
+        legend_margins.block_start);
+    LayoutUnit legend_margin_box_block_size =
+        logical_fragment.BlockSize() + legend_margins.BlockSum();
+    LayoutUnit space_left = borders.block_start - legend_margin_box_block_size;
+    if (space_left > LayoutUnit()) {
+      // If the border is the larger one, though, it will stay put at the
+      // border-box block-start edge of the fieldset. Then it's the legend that
+      // needs to be pushed. We'll center the margin box in this case, to make
+      // sure that both margins remain within the area occupied by the border
+      // also after adjustment.
+      legend_offset.block_offset += space_left / 2;
+    } else {
+      // If the legend is larger than the width of the fieldset block-start
+      // border, the actual padding edge of the fieldset will be moved
+      // accordingly. This will be the block-start offset for the fieldset
+      // contents anonymous box.
+      block_start_padding_edge = legend_margin_box_block_size;
+    }
+
+    container_builder_.AddChild(*result, legend_offset);
+  }
+
+  NGBoxStrut borders_with_legend = borders;
+  borders_with_legend.block_start = block_start_padding_edge;
+  LayoutUnit intrinsic_block_size = borders_with_legend.BlockSum();
+
+  // Proceed with normal fieldset children (excluding the rendered legend). They
+  // all live inside an anonymous child box of the fieldset container.
+  if (auto fieldset_content = Node().GetFieldsetContent()) {
+    NGLogicalSize adjusted_padding_box_size =
+        ShrinkAvailableSize(border_box_size, borders_with_legend);
+    auto child_space =
+        CreateConstraintSpaceForFieldsetContent(adjusted_padding_box_size);
+    auto result = fieldset_content.Layout(child_space, BreakToken());
+    container_builder_.AddChild(*result, borders_with_legend.StartOffset());
+
+    NGFragment logical_fragment(writing_mode, *result->PhysicalFragment());
+    intrinsic_block_size += logical_fragment.BlockSize();
+  } else {
+    // There was no anonymous child to provide the padding, so we have to add it
+    // ourselves.
+    intrinsic_block_size += padding.BlockSum();
+  }
+
+  // Recompute the block-axis size now that we know our content size.
+  border_box_size.block_size = ComputeBlockSizeForFragment(
+      ConstraintSpace(), Style(), intrinsic_block_size);
+
+  // The above computation utility knows nothing about fieldset weirdness. The
+  // legend may eat from the available content box block size. Make room for
+  // that if necessary.
+  LayoutUnit minimum_border_box_block_size =
+      borders_with_legend.BlockSum() + padding.BlockSum();
+  border_box_size.block_size =
+      std::max(border_box_size.block_size, minimum_border_box_block_size);
+
+  container_builder_.SetInlineSize(border_box_size.inline_size);
+  container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
+  container_builder_.SetBlockSize(border_box_size.block_size);
+  container_builder_.SetBorders(borders);
+  container_builder_.SetPadding(padding);
+
+  NGOutOfFlowLayoutPart(&container_builder_, Node().IsAbsoluteContainer(),
+                        Node().IsFixedContainer(), borders_with_legend,
+                        ConstraintSpace(), Style())
+      .Run();
+
+  return container_builder_.ToBoxFragment();
+}
+
+base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize(
+    const MinMaxSizeInput& input) const {
+  // TODO(mstensho): Implement min/max
+  return MinMaxSize();
+}
+
+const NGConstraintSpace
+NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForLegend(
+    NGBlockNode legend,
+    NGLogicalSize available_size) {
+  NGConstraintSpaceBuilder builder(ConstraintSpace());
+  builder.SetAvailableSize(available_size);
+  NGLogicalSize percentage_size =
+      CalculateChildPercentageSize(ConstraintSpace(), Node(), available_size);
+  builder.SetPercentageResolutionSize(percentage_size);
+  builder.SetIsNewFormattingContext(true);
+  builder.SetIsShrinkToFit(true);
+  builder.SetTextDirection(legend.Style().Direction());
+  return builder.ToConstraintSpace(legend.Style().GetWritingMode());
+}
+
+const NGConstraintSpace
+NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForFieldsetContent(
+    NGLogicalSize padding_box_size) {
+  NGConstraintSpaceBuilder builder(ConstraintSpace());
+  builder.SetPercentageResolutionSize(
+      ConstraintSpace().PercentageResolutionSize());
+  builder.SetAvailableSize(padding_box_size);
+  builder.SetIsFixedSizeBlock(padding_box_size.block_size != NGSizeIndefinite);
+  builder.SetIsNewFormattingContext(true);
+  return builder.ToConstraintSpace(ConstraintSpace().GetWritingMode());
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h
new file mode 100644
index 0000000..cfad7de91
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.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 THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FIELDSET_LAYOUT_ALGORITHM_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FIELDSET_LAYOUT_ALGORITHM_H_
+
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
+
+#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h"
+
+namespace blink {
+
+class NGBlockBreakToken;
+class NGBreakToken;
+class NGConstraintSpace;
+
+class CORE_EXPORT NGFieldsetLayoutAlgorithm
+    : public NGLayoutAlgorithm<NGBlockNode,
+                               NGFragmentBuilder,
+                               NGBlockBreakToken> {
+ public:
+  NGFieldsetLayoutAlgorithm(NGBlockNode node,
+                            const NGConstraintSpace& space,
+                            NGBreakToken* break_token = nullptr);
+
+  scoped_refptr<NGLayoutResult> Layout() override;
+
+  base::Optional<MinMaxSize> ComputeMinMaxSize(
+      const MinMaxSizeInput&) const override;
+
+  const NGConstraintSpace CreateConstraintSpaceForLegend(
+      NGBlockNode legend,
+      NGLogicalSize available_size);
+  const NGConstraintSpace CreateConstraintSpaceForFieldsetContent(
+      NGLogicalSize padding_box_size);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FIELDSET_LAYOUT_ALGORITHM_H_
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
new file mode 100644
index 0000000..f964d04
--- /dev/null
+++ b/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
@@ -0,0 +1,442 @@
+// 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 "third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h"
+
+#include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+
+namespace blink {
+namespace {
+
+class NGFieldsetLayoutAlgorithmTest : public NGBaseLayoutAlgorithmTest {
+ protected:
+  void SetUp() override {
+    NGBaseLayoutAlgorithmTest::SetUp();
+    style_ = ComputedStyle::Create();
+    was_fieldset_enabled_ = RuntimeEnabledFeatures::LayoutNGFieldsetEnabled();
+    was_block_fragmentation_enabled_ =
+        RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled();
+    RuntimeEnabledFeatures::SetLayoutNGFieldsetEnabled(true);
+    RuntimeEnabledFeatures::SetLayoutNGBlockFragmentationEnabled(true);
+  }
+
+  void TearDown() override {
+    RuntimeEnabledFeatures::SetLayoutNGFieldsetEnabled(was_fieldset_enabled_);
+    RuntimeEnabledFeatures::SetLayoutNGBlockFragmentationEnabled(
+        was_block_fragmentation_enabled_);
+  }
+
+  scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
+      const NGConstraintSpace& space,
+      NGBlockNode node) {
+    scoped_refptr<NGLayoutResult> result =
+        NGBlockLayoutAlgorithm(node, space).Layout();
+
+    return ToNGPhysicalBoxFragment(result->PhysicalFragment().get());
+  }
+
+  scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
+      Element* element) {
+    NGBlockNode container(ToLayoutBox(element->GetLayoutObject()));
+    NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+        WritingMode::kHorizontalTb, TextDirection::kLtr,
+        NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
+    return RunBlockLayoutAlgorithm(space, container);
+  }
+
+  String DumpFragmentTree(const NGPhysicalBoxFragment* fragment) {
+    NGPhysicalFragment::DumpFlags flags =
+        NGPhysicalFragment::DumpHeaderText | NGPhysicalFragment::DumpSubtree |
+        NGPhysicalFragment::DumpIndentation | NGPhysicalFragment::DumpOffset |
+        NGPhysicalFragment::DumpSize;
+
+    return fragment->DumpFragmentTree(flags);
+  }
+
+  String DumpFragmentTree(Element* element) {
+    auto fragment = RunBlockLayoutAlgorithm(element);
+    return DumpFragmentTree(fragment.get());
+  }
+
+  scoped_refptr<ComputedStyle> style_;
+  bool was_fieldset_enabled_ = false;
+  bool was_block_fragmentation_enabled_ = false;
+};
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, Empty) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset { margin:0; border:3px solid; padding:10px; width:100px; }
+    </style>
+    <div id="container">
+      <fieldset></fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x26
+    offset:0,0 size:126x26
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, NoLegend) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset { margin:0; border:3px solid; padding:10px; width:100px; }
+    </style>
+    <div id="container">
+      <fieldset>
+        <div style="height:100px;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x126
+    offset:0,0 size:126x126
+      offset:3,3 size:120x120
+        offset:10,10 size:100x100
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, Legend) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset { margin:0; border:3px solid; padding:10px; width:100px; }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend style="padding:0; width:50px; height:200px;"></legend>
+        <div style="height:100px;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x323
+    offset:0,0 size:126x323
+      offset:13,0 size:50x200
+      offset:3,200 size:120x120
+        offset:10,10 size:100x100
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, SmallLegendLargeBorder) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset { margin:0; border:40px solid; padding:10px; width:100px; }
+      legend { padding:0; width:10px; height:10px;
+               margin-top:5px; margin-bottom:15px; }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend></legend>
+        <div style="height:100px;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x200
+    offset:0,0 size:200x200
+      offset:50,10 size:10x10
+      offset:40,40 size:120x120
+        offset:10,10 size:100x100
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendOrthogonalWritingMode) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset { margin:0; border:3px solid; padding:10px; width:100px; }
+      legend { writing-mode:vertical-rl; padding:0; margin:10px 15px 20px 30px;
+               width:10px; height:50px; }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend></legend>
+        <div style="height:100px;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x203
+    offset:0,0 size:126x203
+      offset:43,10 size:10x50
+      offset:3,80 size:120x120
+        offset:10,10 size:100x100
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, VerticalLr) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset { writing-mode:vertical-lr; margin:0; border:3px solid;
+                 padding:10px; height:100px; }
+      legend { padding:0; margin:10px 15px 20px 30px; width:10px; height:50px; }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend></legend>
+        <div style="width:100px;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x126
+    offset:0,0 size:178x126
+      offset:30,23 size:10x50
+      offset:55,3 size:120x120
+        offset:10,10 size:100x100
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, VerticalRl) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset { writing-mode:vertical-rl; margin:0; border:3px solid;
+                 padding:10px; height:100px; }
+      legend { padding:0; margin:10px 15px 20px 30px; width:10px; height:50px; }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend></legend>
+        <div style="width:100px;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x126
+    offset:0,0 size:178x126
+      offset:153,23 size:10x50
+      offset:3,3 size:120x120
+        offset:10,10 size:100x100
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAutoSize) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset { margin:0; border:3px solid; padding:10px; width:100px; }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend style="padding:0;">
+          <div style="float:left; width:25px; height:200px;"></div>
+          <div style="float:left; width:25px; height:200px;"></div>
+        </legend>
+        <div style="height:100px;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x323
+    offset:0,0 size:126x323
+      offset:13,0 size:50x200
+        offset:0,0 size:25x200
+        offset:25,0 size:25x200
+        offset:50,0 size:0x0
+      offset:3,200 size:120x120
+        offset:10,10 size:100x100
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, PercentageHeightChild) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset {
+        margin:0; border:3px solid; padding:10px; width:100px; height:100px;
+      }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend style="padding:0; width:30px; height:30px;"></legend>
+        <div style="height:100%;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x126
+    offset:0,0 size:126x126
+      offset:13,0 size:30x30
+      offset:3,30 size:120x93
+        offset:10,10 size:100x73
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+// Disabled because out-of-flow positioned objects enter legacy code (regardless
+// of the out-of-flow positioned object being laid out by NG or not). Invoking
+// layout on our own outside of the lifecycle machinery will eventually fail a
+// CHECK in SubtreeLayoutScope::SubtreeLayoutScope().
+TEST_F(NGFieldsetLayoutAlgorithmTest, DISABLED_AbsposChild) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset {
+        position:relative; margin:0; border:3px solid; padding:10px;
+        width:100px; height:100px;
+      }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend style="padding:0; width:30px; height:30px;"></legend>
+        <div style="position:absolute; top:0; right:0; bottom:0; left:0;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x126
+    offset:0,0 size:126x126
+      offset:13,0 size:30x30
+      offset:3,30 size:120x93
+      offset:3,30 size:120x93
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+// Used height needs to be adjusted to encompass the legend, if specified height
+// requests a lower height than that.
+TEST_F(NGFieldsetLayoutAlgorithmTest, ZeroHeight) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset {
+        margin:0; border:3px solid; padding:10px; width:100px; height:0;
+      }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend style="padding:0; width:30px; height:30px;"></legend>
+        <div style="height:200px;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x53
+    offset:0,0 size:126x53
+      offset:13,0 size:30x30
+      offset:3,30 size:120x0
+        offset:10,10 size:100x200
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+// Used height needs to be adjusted to encompass the legend, if specified height
+// requests a lower max-height than that.
+TEST_F(NGFieldsetLayoutAlgorithmTest, ZeroMaxHeight) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset {
+        margin:0; border:3px solid; padding:10px; width:100px; max-height:0;
+      }
+    </style>
+    <div id="container">
+      <fieldset>
+        <legend style="padding:0; width:30px; height:30px;"></legend>
+        <div style="height:200px;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x53
+    offset:0,0 size:126x53
+      offset:13,0 size:30x30
+      offset:3,30 size:120x220
+        offset:10,10 size:100x200
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+// Things inside legends and fieldsets are treated as if there was no fieldsets
+// and legends involved, as far as the percentage height quirk is concerned.
+TEST_F(NGFieldsetLayoutAlgorithmTest, PercentHeightQuirks) {
+  GetDocument().SetCompatibilityMode(Document::kQuirksMode);
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset {
+        margin:0; border:3px solid; padding:10px; width:100px;
+      }
+    </style>
+    <div id="container" style="height:200px;">
+      <fieldset>
+        <legend style="padding:0;">
+          <div style="width:100px; height:50%;"></div>
+        </legend>
+        <div style="width:40px; height:20%;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x200
+    offset:0,0 size:126x163
+      offset:13,0 size:100x100
+        offset:0,0 size:100x100
+      offset:3,100 size:120x60
+        offset:10,10 size:40x40
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+// Legends are treated as regular elements, as far as the percentage height
+// quirk is concerned.
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendPercentHeightQuirks) {
+  GetDocument().SetCompatibilityMode(Document::kQuirksMode);
+  SetBodyInnerHTML(R"HTML(
+    <style>
+      fieldset {
+        margin:0; border:3px solid; padding:10px; width:100px;
+      }
+    </style>
+    <div id="container" style="height:200px;">
+      <fieldset>
+        <legend style="padding:0; width:100px; height:50%;"></legend>
+        <div style="width:40px; height:20%;"></div>
+      </fieldset>
+    </div>
+  )HTML");
+
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x200
+    offset:0,0 size:126x163
+      offset:13,0 size:100x100
+      offset:3,100 size:120x60
+        offset:10,10 size:40x40
+)DUMP";
+  EXPECT_EQ(expectation, dump);
+}
+
+}  // anonymous namespace
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
index 1e7e015..08c9990 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
@@ -107,6 +107,10 @@
   return IsBlock() && box_->IsTableCell();
 }
 
+bool NGLayoutInputNode::IsFieldsetContainer() const {
+  return IsBlock() && box_->IsLayoutNGFieldset();
+}
+
 bool NGLayoutInputNode::IsAnonymousBlock() const {
   return box_->IsAnonymousBlock();
 }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index 0402f88..55d1494 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -73,6 +73,7 @@
   bool IsListMarker() const;
   bool ListMarkerOccupiesWholeLine() const;
   bool IsTableCell() const;
+  bool IsFieldsetContainer() const;
   bool IsAnonymousBlock() const;
 
   // If the node is a quirky container for margin collapsing, see:
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
index 71c02828..06f060ca 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
@@ -210,6 +210,8 @@
 // values and over-constrainedness. This uses the available size from the
 // constraint space and inline size to compute the margins that are auto, if
 // any, and adjusts the given NGBoxStrut accordingly.
+// available_inline_size, inline_size, and margins are all in the
+// containing_block's writing mode.
 CORE_EXPORT void ResolveInlineMargins(
     const ComputedStyle& child_style,
     const ComputedStyle& containing_block_style,
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
index 042f065..4353b24 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
@@ -27,6 +27,7 @@
 #include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
 #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
 #include "third_party/blink/renderer/core/paint/paint_info.h"
+#include "third_party/blink/renderer/core/svg/svg_clip_path_element.h"
 #include "third_party/blink/renderer/core/svg/svg_geometry_element.h"
 #include "third_party/blink/renderer/core/svg/svg_use_element.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_record.h"
@@ -214,6 +215,13 @@
   }
 }
 
+SVGUnitTypes::SVGUnitType LayoutSVGResourceClipper::ClipPathUnits() const {
+  return ToSVGClipPathElement(GetElement())
+      ->clipPathUnits()
+      ->CurrentValue()
+      ->EnumValue();
+}
+
 AffineTransform LayoutSVGResourceClipper::CalculateClipTransform(
     const FloatRect& reference_box) const {
   AffineTransform transform =
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
index 4a265c56..b7913ab 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
@@ -21,11 +21,13 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_CLIPPER_H_
 
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
-#include "third_party/blink/renderer/core/svg/svg_clip_path_element.h"
+#include "third_party/blink/renderer/core/svg/svg_unit_types.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
 namespace blink {
 
+class SVGClipPathElement;
+
 class LayoutSVGResourceClipper final : public LayoutSVGResourceContainer {
  public:
   explicit LayoutSVGResourceClipper(SVGClipPathElement*);
@@ -42,12 +44,7 @@
 
   bool HitTestClipContent(const FloatRect&, const FloatPoint&);
 
-  SVGUnitTypes::SVGUnitType ClipPathUnits() const {
-    return ToSVGClipPathElement(GetElement())
-        ->clipPathUnits()
-        ->CurrentValue()
-        ->EnumValue();
-  }
+  SVGUnitTypes::SVGUnitType ClipPathUnits() const;
   AffineTransform CalculateClipTransform(const FloatRect& reference_box) const;
 
   base::Optional<Path> AsPath();
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
index a9559a57..74444393 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
@@ -85,13 +85,10 @@
 }
 
 FloatRect LayoutSVGResourceFilter::ResourceBoundingBox(
-    const LayoutObject* object) {
-  if (SVGFilterElement* element = ToSVGFilterElement(GetElement()))
-    return SVGLengthContext::ResolveRectangle<SVGFilterElement>(
-        element, element->filterUnits()->CurrentValue()->EnumValue(),
-        object->ObjectBoundingBox());
-
-  return FloatRect();
+    const FloatRect& reference_box) const {
+  const auto* filter_element = ToSVGFilterElement(GetElement());
+  return SVGLengthContext::ResolveRectangle(filter_element, FilterUnits(),
+                                            reference_box);
 }
 
 SVGUnitTypes::SVGUnitType LayoutSVGResourceFilter::FilterUnits() const {
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
index 23372b07..0152f3e 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
@@ -82,7 +82,7 @@
   void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override;
   bool RemoveClientFromCache(SVGResourceClient&) override;
 
-  FloatRect ResourceBoundingBox(const LayoutObject*);
+  FloatRect ResourceBoundingBox(const FloatRect& reference_box) const;
 
   SVGUnitTypes::SVGUnitType FilterUnits() const;
   SVGUnitTypes::SVGUnitType PrimitiveUnits() const;
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
index ae7d043..62810559 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
@@ -23,6 +23,7 @@
 #include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
 #include "third_party/blink/renderer/core/paint/svg_object_painter.h"
 #include "third_party/blink/renderer/core/svg/svg_element.h"
+#include "third_party/blink/renderer/core/svg/svg_mask_element.h"
 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_record.h"
 #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
@@ -49,11 +50,7 @@
     AffineTransform& content_transformation,
     const FloatRect& target_bounding_box,
     GraphicsContext& context) {
-  SVGUnitTypes::SVGUnitType content_units = ToSVGMaskElement(GetElement())
-                                                ->maskContentUnits()
-                                                ->CurrentValue()
-                                                ->EnumValue();
-  if (content_units == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
+  if (MaskContentUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
     content_transformation.Translate(target_bounding_box.X(),
                                      target_bounding_box.Y());
     content_transformation.ScaleNonUniform(target_bounding_box.Width(),
@@ -98,16 +95,27 @@
   }
 }
 
+SVGUnitTypes::SVGUnitType LayoutSVGResourceMasker::MaskUnits() const {
+  return ToSVGMaskElement(GetElement())
+      ->maskUnits()
+      ->CurrentValue()
+      ->EnumValue();
+}
+
+SVGUnitTypes::SVGUnitType LayoutSVGResourceMasker::MaskContentUnits() const {
+  return ToSVGMaskElement(GetElement())
+      ->maskContentUnits()
+      ->CurrentValue()
+      ->EnumValue();
+}
+
 FloatRect LayoutSVGResourceMasker::ResourceBoundingBox(
-    const LayoutObject* object) {
+    const FloatRect& reference_box) {
   SVGMaskElement* mask_element = ToSVGMaskElement(GetElement());
   DCHECK(mask_element);
 
-  FloatRect object_bounding_box = object->ObjectBoundingBox();
-  FloatRect mask_boundaries =
-      SVGLengthContext::ResolveRectangle<SVGMaskElement>(
-          mask_element, mask_element->maskUnits()->CurrentValue()->EnumValue(),
-          object_bounding_box);
+  FloatRect mask_boundaries = SVGLengthContext::ResolveRectangle(
+      mask_element, MaskUnits(), reference_box);
 
   // Resource was not layouted yet. Give back clipping rect of the mask.
   if (SelfNeedsLayout())
@@ -117,12 +125,10 @@
     CalculateMaskContentVisualRect();
 
   FloatRect mask_rect = mask_content_boundaries_;
-  if (mask_element->maskContentUnits()->CurrentValue()->Value() ==
-      SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
+  if (MaskContentUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
     AffineTransform transform;
-    transform.Translate(object_bounding_box.X(), object_bounding_box.Y());
-    transform.ScaleNonUniform(object_bounding_box.Width(),
-                              object_bounding_box.Height());
+    transform.Translate(reference_box.X(), reference_box.Y());
+    transform.ScaleNonUniform(reference_box.Width(), reference_box.Height());
     mask_rect = transform.MapRect(mask_rect);
   }
 
diff --git a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
index eea70d1..70442a2 100644
--- a/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
+++ b/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
@@ -21,7 +21,6 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_MASKER_H_
 
 #include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
-#include "third_party/blink/renderer/core/svg/svg_mask_element.h"
 #include "third_party/blink/renderer/core/svg/svg_unit_types.h"
 #include "third_party/blink/renderer/platform/geometry/float_rect.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
@@ -30,6 +29,7 @@
 
 class AffineTransform;
 class GraphicsContext;
+class SVGMaskElement;
 
 class LayoutSVGResourceMasker final : public LayoutSVGResourceContainer {
  public:
@@ -40,20 +40,10 @@
 
   void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override;
 
-  FloatRect ResourceBoundingBox(const LayoutObject*);
+  FloatRect ResourceBoundingBox(const FloatRect& reference_box);
 
-  SVGUnitTypes::SVGUnitType MaskUnits() const {
-    return ToSVGMaskElement(GetElement())
-        ->maskUnits()
-        ->CurrentValue()
-        ->EnumValue();
-  }
-  SVGUnitTypes::SVGUnitType MaskContentUnits() const {
-    return ToSVGMaskElement(GetElement())
-        ->maskContentUnits()
-        ->CurrentValue()
-        ->EnumValue();
-  }
+  SVGUnitTypes::SVGUnitType MaskUnits() const;
+  SVGUnitTypes::SVGUnitType MaskContentUnits() const;
 
   static const LayoutSVGResourceType kResourceType = kMaskerResourceType;
   LayoutSVGResourceType ResourceType() const override { return kResourceType; }
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
index 76eb82d..2fb3a01 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -41,6 +41,7 @@
 #include "third_party/blink/renderer/core/paint/paint_layer.h"
 #include "third_party/blink/renderer/core/style/shape_clip_path_operation.h"
 #include "third_party/blink/renderer/core/svg/svg_element.h"
+#include "third_party/blink/renderer/core/svg/svg_length_context.h"
 #include "third_party/blink/renderer/platform/graphics/stroke_data.h"
 #include "third_party/blink/renderer/platform/transforms/transform_state.h"
 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
@@ -391,16 +392,20 @@
   if (!resources)
     return;
 
-  if (LayoutSVGResourceFilter* filter = resources->Filter())
-    visual_rect = filter->ResourceBoundingBox(&layout_object);
+  if (LayoutSVGResourceFilter* filter = resources->Filter()) {
+    visual_rect =
+        filter->ResourceBoundingBox(layout_object.ObjectBoundingBox());
+  }
 
   if (LayoutSVGResourceClipper* clipper = resources->Clipper()) {
     visual_rect.Intersect(
         clipper->ResourceBoundingBox(layout_object.ObjectBoundingBox()));
   }
 
-  if (LayoutSVGResourceMasker* masker = resources->Masker())
-    visual_rect.Intersect(masker->ResourceBoundingBox(&layout_object));
+  if (LayoutSVGResourceMasker* masker = resources->Masker()) {
+    visual_rect.Intersect(
+        masker->ResourceBoundingBox(layout_object.ObjectBoundingBox()));
+  }
 }
 
 bool SVGLayoutSupport::HasFilterResource(const LayoutObject& object) {
diff --git a/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc b/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
index 6b685d8..c77274e 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
@@ -735,6 +735,7 @@
       SVGResourcesCache::CachedResourcesForLayoutObject(object);
   if (!resources)
     return;
+  const FloatRect reference_box = object.ObjectBoundingBox();
   const ComputedStyle& style = object.StyleRef();
   TreeScope& tree_scope = object.GetDocument();
   if (LayoutSVGResourceMasker* masker = resources->Masker()) {
@@ -744,7 +745,7 @@
                            tree_scope);
     ts << " ";
     WriteStandardPrefix(ts, *masker, 0);
-    ts << " " << masker->ResourceBoundingBox(&object) << "\n";
+    ts << " " << masker->ResourceBoundingBox(reference_box) << "\n";
   }
   if (LayoutSVGResourceClipper* clipper = resources->Clipper()) {
     DCHECK(style.ClipPath());
@@ -758,8 +759,7 @@
     WriteNameAndQuotedValue(ts, "clipPath", id);
     ts << " ";
     WriteStandardPrefix(ts, *clipper, 0);
-    ts << " " << clipper->ResourceBoundingBox(object.ObjectBoundingBox())
-       << "\n";
+    ts << " " << clipper->ResourceBoundingBox(reference_box) << "\n";
   }
   if (LayoutSVGResourceFilter* filter = resources->Filter()) {
     DCHECK(style.HasFilter());
@@ -775,7 +775,7 @@
     WriteNameAndQuotedValue(ts, "filter", id);
     ts << " ";
     WriteStandardPrefix(ts, *filter, 0);
-    ts << " " << filter->ResourceBoundingBox(&object) << "\n";
+    ts << " " << filter->ResourceBoundingBox(reference_box) << "\n";
   }
 }
 
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources.cc b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
index 2d2add6f..8b287a35 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_resources.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources.cc
@@ -291,15 +291,8 @@
   if (!HasResourceData())
     return 0;
 
-  if (linked_resource_) {
-    DCHECK(!clipper_filter_masker_data_);
-    DCHECK(!marker_data_);
-    DCHECK(!fill_stroke_data_);
-    linked_resource_->RemoveClientFromCache(client);
-    // The only linked resources are gradients and patterns, i.e
-    // always a paint server.
-    return SVGResourceClient::kPaintInvalidation;
-  }
+  // We never call this method for the elements where this would be non-null.
+  DCHECK(!linked_resource_);
 
   InvalidationModeMask invalidation_flags =
       RemoveClientFromCacheAffectingObjectBounds(client);
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
index 9cc13bbf..37932071f 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
@@ -32,7 +32,7 @@
 
 SVGResourcesCache::~SVGResourcesCache() = default;
 
-void SVGResourcesCache::AddResourcesFromLayoutObject(
+bool SVGResourcesCache::AddResourcesFromLayoutObject(
     LayoutObject& object,
     const ComputedStyle& style) {
   DCHECK(!cache_.Contains(&object));
@@ -41,10 +41,7 @@
   std::unique_ptr<SVGResources> new_resources =
       SVGResources::BuildResources(object, style);
   if (!new_resources)
-    return;
-
-  // The new resource may cause new paint property nodes.
-  object.SetNeedsPaintPropertyUpdate();
+    return false;
 
   // Put object in cache.
   SVGResources* resources =
@@ -59,15 +56,20 @@
     if (solver.FindCycle(resource_container))
       resources->ClearReferencesTo(resource_container);
   }
+  return true;
 }
 
-void SVGResourcesCache::RemoveResourcesFromLayoutObject(LayoutObject& object) {
+bool SVGResourcesCache::RemoveResourcesFromLayoutObject(LayoutObject& object) {
   std::unique_ptr<SVGResources> resources = cache_.Take(&object);
-  if (!resources)
-    return;
+  return !!resources;
+}
 
-  // Removal of the resource may cause removal of paint property nodes.
-  object.SetNeedsPaintPropertyUpdate();
+bool SVGResourcesCache::UpdateResourcesFromLayoutObject(
+    LayoutObject& object,
+    const ComputedStyle& new_style) {
+  bool did_update = RemoveResourcesFromLayoutObject(object);
+  did_update |= AddResourcesFromLayoutObject(object, new_style);
+  return did_update;
 }
 
 static inline SVGResourcesCache& ResourcesCache(Document& document) {
@@ -135,8 +137,8 @@
   // rebuild individual resources, instead of all of them.
   if (LayoutObjectCanHaveResources(layout_object)) {
     SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
-    cache.RemoveResourcesFromLayoutObject(layout_object);
-    cache.AddResourcesFromLayoutObject(layout_object, new_style);
+    if (cache.UpdateResourcesFromLayoutObject(layout_object, new_style))
+      layout_object.SetNeedsPaintPropertyUpdate();
   }
 
   // If this layoutObject is the child of ResourceContainer and it require
@@ -162,8 +164,10 @@
   DCHECK(LayoutObjectCanHaveResources(layout_object));
 
   SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
-  cache.RemoveResourcesFromLayoutObject(layout_object);
-  cache.AddResourcesFromLayoutObject(layout_object, layout_object.StyleRef());
+  if (cache.UpdateResourcesFromLayoutObject(layout_object,
+                                            layout_object.StyleRef())) {
+    layout_object.SetNeedsPaintPropertyUpdate();
+  }
 
   LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
       layout_object, true);
@@ -179,7 +183,8 @@
   if (!LayoutObjectCanHaveResources(layout_object))
     return;
   SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
-  cache.AddResourcesFromLayoutObject(layout_object, new_style);
+  if (cache.AddResourcesFromLayoutObject(layout_object, new_style))
+    layout_object.SetNeedsPaintPropertyUpdate();
 }
 
 void SVGResourcesCache::ClientWillBeRemovedFromTree(
@@ -192,7 +197,8 @@
   if (!LayoutObjectCanHaveResources(layout_object))
     return;
   SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
-  cache.RemoveResourcesFromLayoutObject(layout_object);
+  if (cache.RemoveResourcesFromLayoutObject(layout_object))
+    layout_object.SetNeedsPaintPropertyUpdate();
 }
 
 void SVGResourcesCache::ClientDestroyed(LayoutObject& layout_object) {
@@ -228,8 +234,7 @@
     const ComputedStyle& style) {
   DCHECK(!styles_are_equal_);
   SVGResourcesCache& cache = ResourcesCache(layout_object_.GetDocument());
-  cache.RemoveResourcesFromLayoutObject(layout_object_);
-  cache.AddResourcesFromLayoutObject(layout_object_, style);
+  cache.UpdateResourcesFromLayoutObject(layout_object_, style);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
index eec4f65..42b85c7e 100644
--- a/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
+++ b/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
@@ -84,8 +84,9 @@
   };
 
  private:
-  void AddResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&);
-  void RemoveResourcesFromLayoutObject(LayoutObject&);
+  bool AddResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&);
+  bool RemoveResourcesFromLayoutObject(LayoutObject&);
+  bool UpdateResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&);
 
   typedef HashMap<const LayoutObject*, std::unique_ptr<SVGResources>> CacheMap;
   CacheMap cache_;
diff --git a/third_party/blink/renderer/core/page/spatial_navigation.cc b/third_party/blink/renderer/core/page/spatial_navigation.cc
index c863077..8c00d17 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/frame/visual_viewport.h"
 #include "third_party/blink/renderer/core/html/html_area_element.h"
 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
 #include "third_party/blink/renderer/core/html/html_image_element.h"
@@ -712,32 +713,27 @@
              : nullptr;
 };
 
-// The rect of the visual viewport given in the root frame's coordinate space.
+// The visual viewport's rect (given in the root frame's coordinate space).
 LayoutRect RootViewport(const LocalFrame* current_frame) {
-  LocalFrameView* root_frame_view = current_frame->LocalFrameRoot().View();
-  const LayoutRect root_doc_rect(
-      root_frame_view->GetScrollableArea()->VisibleContentRect());
-  // Convert the root frame's visible rect from document space -> frame space.
-  // For the root frame, frame space == root frame space, obviously.
-  LayoutRect frame_rect = root_frame_view->DocumentToFrame(root_doc_rect);
-  return frame_rect;
+  return LayoutRect(
+      current_frame->GetPage()->GetVisualViewport().VisibleRect());
 }
 
 // Spatnav uses this rectangle to measure distances to focus candidates.
 // The search origin is either activeElement F itself, if it's being at least
 // partially visible, or else, its first [partially] visible scroller. If both
 // F and its enclosing scroller are completely off-screen, we recurse to the
-// scroller’s scroller ... all the way up unil the root frame's document.
+// scroller’s scroller ... all the way up until the root frame's document.
 // The root frame's document is a good base case because it's, per definition,
 // a visible scrollable area.
-LayoutRect SearchOrigin(const LayoutRect visible_root_frame,
+LayoutRect SearchOrigin(const LayoutRect viewport_rect_of_root_frame,
                         Node* focus_node,
                         const WebFocusType direction) {
   if (!focus_node) {
     // Search from one of the visual viewport's edges towards the navigated
     // direction. For example, UP makes spatnav search upwards, starting at the
     // visual viewport's bottom.
-    return OppositeEdge(direction, visible_root_frame);
+    return OppositeEdge(direction, viewport_rect_of_root_frame);
   }
 
   LayoutRect box_in_root_frame;
@@ -759,16 +755,17 @@
     // We found the first box that encloses focus and is [partially] visible.
     if (area_element || IsScrollableAreaOrDocument(focus_node)) {
       // When searching a container, we start from one of its sides.
-      return OppositeEdge(direction,
-                          Intersection(box_in_root_frame, visible_root_frame),
-                          thickness);
+      return OppositeEdge(
+          direction,
+          Intersection(box_in_root_frame, viewport_rect_of_root_frame),
+          thickness);
     }
-    return Intersection(box_in_root_frame, visible_root_frame);
+    return Intersection(box_in_root_frame, viewport_rect_of_root_frame);
   }
 
   // Try a higher "focus-enclosing" scroller.
   Node* container = ScrollableAreaOrDocumentOf(focus_node);
-  return SearchOrigin(visible_root_frame, container, direction);
+  return SearchOrigin(viewport_rect_of_root_frame, container, direction);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/spatial_navigation_test.cc b/third_party/blink/renderer/core/page/spatial_navigation_test.cc
index 1cdc0112..2b33e2dc 100644
--- a/third_party/blink/renderer/core/page/spatial_navigation_test.cc
+++ b/third_party/blink/renderer/core/page/spatial_navigation_test.cc
@@ -46,6 +46,23 @@
   }
 };
 
+TEST_F(SpatialNavigationTest, RootFramesVisualViewport) {
+  // Test RootViewport with a pinched viewport.
+  VisualViewport& visual_viewport = GetFrame().GetPage()->GetVisualViewport();
+  visual_viewport.SetScale(2);
+  visual_viewport.SetLocation(FloatPoint(200, 200));
+
+  LocalFrameView* root_frame_view = GetFrame().LocalFrameRoot().View();
+  const LayoutRect roots_visible_doc_rect(
+      root_frame_view->GetScrollableArea()->VisibleContentRect());
+  // Convert the root frame's visible rect from document space -> frame space.
+  // For the root frame, frame space == root frame space, obviously.
+  LayoutRect viewport_rect_of_root_frame =
+      root_frame_view->DocumentToFrame(roots_visible_doc_rect);
+
+  EXPECT_EQ(viewport_rect_of_root_frame, RootViewport(&GetFrame()));
+}
+
 TEST_F(SpatialNavigationTest, FindContainerWhenEnclosingContainerIsDocument) {
   SetBodyInnerHTML(
       "<!DOCTYPE html>"
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
index d11dde3..32f33ec 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_requirements_updater.cc
@@ -427,7 +427,8 @@
   bool will_have_foreground_layer = false;
 
   bool needs_recursion_for_composited_scrolling_plus_fixed_or_sticky =
-      layer->HasDescendantWithStickyOrFixed() &&
+      (layer->HasFixedPositionDescendant() ||
+       layer->HasStickyPositionDescendant()) &&
       (has_non_root_composited_scrolling_ancestor ||
        (layer->GetScrollableArea() &&
         layer->GetScrollableArea()->NeedsCompositedScrolling()));
diff --git a/third_party/blink/renderer/core/paint/css_mask_painter.cc b/third_party/blink/renderer/core/paint/css_mask_painter.cc
index 1fa15cb..5f092f0d 100644
--- a/third_party/blink/renderer/core/paint/css_mask_painter.cc
+++ b/third_party/blink/renderer/core/paint/css_mask_painter.cc
@@ -22,8 +22,10 @@
     SVGResources* resources =
         SVGResourcesCache::CachedResourcesForLayoutObject(object);
     LayoutSVGResourceMasker* masker = resources ? resources->Masker() : nullptr;
-    if (masker)
-      return EnclosingIntRect(masker->ResourceBoundingBox(&object));
+    if (masker) {
+      return EnclosingIntRect(
+          masker->ResourceBoundingBox(object.ObjectBoundingBox()));
+    }
   }
 
   if (object.IsSVGChild() && !object.IsSVGForeignObject())
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
index 59551bc..7edc072 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.cc
@@ -165,23 +165,67 @@
 
 NGPaintFragment::~NGPaintFragment() = default;
 
-scoped_refptr<NGPaintFragment> NGPaintFragment::Create(
+scoped_refptr<NGPaintFragment> NGPaintFragment::CreateOrReuse(
     scoped_refptr<const NGPhysicalFragment> fragment,
-    NGPhysicalOffset offset) {
+    NGPhysicalOffset offset,
+    NGPaintFragment* parent,
+    scoped_refptr<NGPaintFragment> previous_instance,
+    bool* populate_children) {
   DCHECK(fragment);
 
-  scoped_refptr<NGPaintFragment> paint_fragment =
-      base::AdoptRef(new NGPaintFragment(std::move(fragment), offset, nullptr));
+  // If the previous instance is given, check if it is re-usable.
+  // Re-using NGPaintFragment allows the paint system to identify objects.
+  if (previous_instance) {
+    DCHECK_EQ(previous_instance->parent_, parent);
 
-  HashMap<const LayoutObject*, NGPaintFragment*> last_fragment_map;
-  paint_fragment->PopulateDescendants(NGPhysicalOffset(),
-                                      &last_fragment_map);
+    // If the physical fragment was re-used, re-use the paint fragment as well.
+    if (&previous_instance->PhysicalFragment() == fragment.get()) {
+      previous_instance->offset_ = offset;
+      previous_instance->next_for_same_layout_object_ = nullptr;
+      // No need to re-populate children because NGPhysicalFragment is
+      // immutable and thus children should not have been changed.
+      *populate_children = false;
+      return previous_instance;
+    }
+
+    // If the LayoutObject are the same, the new paint fragment should have the
+    // same DisplayItemClient identity as the previous instance.
+    if (previous_instance->GetLayoutObject() == fragment->GetLayoutObject()) {
+      previous_instance->physical_fragment_ = std::move(fragment);
+      previous_instance->offset_ = offset;
+      previous_instance->next_for_same_layout_object_ = nullptr;
+      if (!*populate_children)
+        previous_instance->children_.clear();
+      return previous_instance;
+    }
+  }
+
+  return base::AdoptRef(
+      new NGPaintFragment(std::move(fragment), offset, parent));
+}
+
+scoped_refptr<NGPaintFragment> NGPaintFragment::Create(
+    scoped_refptr<const NGPhysicalFragment> fragment,
+    NGPhysicalOffset offset,
+    scoped_refptr<NGPaintFragment> previous_instance) {
+  DCHECK(fragment);
+
+  bool populate_children = fragment->IsContainer();
+  scoped_refptr<NGPaintFragment> paint_fragment =
+      CreateOrReuse(std::move(fragment), offset, nullptr,
+                    std::move(previous_instance), &populate_children);
+
+  if (populate_children) {
+    HashMap<const LayoutObject*, NGPaintFragment*> last_fragment_map;
+    paint_fragment->PopulateDescendants(NGPhysicalOffset(), &last_fragment_map);
+  }
 
   return paint_fragment;
 }
 
-void NGPaintFragment::UpdatePhysicalFragmentFromCachedLayoutResult(
-    scoped_refptr<const NGPhysicalFragment> fragment) {
+void NGPaintFragment::UpdateFromCachedLayoutResult(
+    scoped_refptr<const NGPhysicalFragment> fragment,
+    NGPhysicalOffset offset) {
   DCHECK(fragment);
 
 #if DCHECK_IS_ON()
@@ -196,7 +240,9 @@
   }
 #endif
 
-  physical_fragment_ = fragment;
+  DCHECK_EQ(physical_fragment_.get(), fragment.get());
+  physical_fragment_ = std::move(fragment);
+  offset_ = offset;
 }
 
 NGPaintFragment* NGPaintFragment::Last(const NGBreakToken& break_token) {
@@ -217,6 +263,29 @@
   }
 }
 
+scoped_refptr<NGPaintFragment>* NGPaintFragment::Find(
+    scoped_refptr<NGPaintFragment>* fragment,
+    const NGBreakToken* break_token) {
+  DCHECK(fragment);
+
+  if (!break_token)
+    return fragment;
+
+  while (true) {
+    // TODO(kojii): Sometimes an unknown break_token is given. Need to
+    // investigate why, and handle appropriately. For now, just keep it to avoid
+    // crashes and use-after-free.
+    if (!*fragment)
+      return fragment;
+
+    scoped_refptr<NGPaintFragment>* next = &(*fragment)->next_fragmented_;
+    if ((*fragment)->PhysicalFragment().BreakToken() == break_token)
+      return next;
+    fragment = next;
+  }
+  NOTREACHED();
+}
+
 void NGPaintFragment::SetNext(scoped_refptr<NGPaintFragment> fragment) {
   next_fragmented_ = std::move(fragment);
 }
@@ -258,17 +327,21 @@
 void NGPaintFragment::PopulateDescendants(
     const NGPhysicalOffset inline_offset_to_container_box,
     HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map) {
-  DCHECK(children_.IsEmpty());
   const NGPhysicalFragment& fragment = PhysicalFragment();
-  if (!fragment.IsContainer())
-    return;
+  DCHECK(fragment.IsContainer());
   const NGPhysicalContainerFragment& container =
       ToNGPhysicalContainerFragment(fragment);
   children_.ReserveCapacity(container.Children().size());
 
-  for (const auto& child_fragment : container.Children()) {
-    scoped_refptr<NGPaintFragment> child = base::AdoptRef(new NGPaintFragment(
-        child_fragment.get(), child_fragment.Offset(), this));
+  unsigned child_index = 0;
+  for (const NGLink& child_fragment : container.Children()) {
+    bool populate_children = child_fragment->IsContainer() &&
+                             !child_fragment->IsBlockFormattingContextRoot();
+    scoped_refptr<NGPaintFragment> child = CreateOrReuse(
+        child_fragment.get(), child_fragment.Offset(), this,
+        child_index < children_.size() ? std::move(children_[child_index])
+                                       : nullptr,
+        &populate_children);
 
     if (!child_fragment->IsFloating() &&
         !child_fragment->IsOutOfFlowPositioned() &&
@@ -281,18 +354,20 @@
           inline_offset_to_container_box + child_fragment.Offset();
     }
 
-    // Recurse children, except when this is a block formatting context root.
-    // TODO(kojii): At the block formatting context root, children may be for
-    // NGPaint, LayoutNG but not for NGPaint, or legacy. In order to get the
-    // maximum test coverage, split the NGPaintFragment tree at all possible
-    // engine boundaries.
-    if (!child_fragment->IsBlockFormattingContextRoot()) {
+    if (populate_children) {
       child->PopulateDescendants(child->inline_offset_to_container_box_,
                                  last_fragment_map);
     }
 
-    children_.push_back(std::move(child));
+    if (child_index < children_.size())
+      children_[child_index] = std::move(child);
+    else
+      children_.push_back(std::move(child));
+    ++child_index;
   }
+
+  if (child_index < children_.size())
+    children_.resize(child_index);
 }
 
 // Add to a linked list for each LayoutObject.
@@ -300,6 +375,7 @@
     LayoutObject* layout_object,
     HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map) {
   DCHECK(layout_object);
+  DCHECK(!next_for_same_layout_object_);
 
   // TODO(kojii): The LayoutObject is inline, except for column container
   // fragment. We should have better way to distinguish it, probably after we
diff --git a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
index d14d746..d2fafd8 100644
--- a/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
+++ b/third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h
@@ -46,20 +46,24 @@
 
   static scoped_refptr<NGPaintFragment> Create(
       scoped_refptr<const NGPhysicalFragment>,
-      NGPhysicalOffset offset);
+      NGPhysicalOffset offset,
+      scoped_refptr<NGPaintFragment> previous_instance = nullptr);
 
   const NGPhysicalFragment& PhysicalFragment() const {
     return *physical_fragment_;
   }
 
-  void UpdatePhysicalFragmentFromCachedLayoutResult(
-      scoped_refptr<const NGPhysicalFragment>);
+  void UpdateFromCachedLayoutResult(
+      scoped_refptr<const NGPhysicalFragment> fragment,
+      NGPhysicalOffset offset);
 
   // Next/last fragment for  when this is fragmented.
   NGPaintFragment* Next() { return next_fragmented_.get(); }
   void SetNext(scoped_refptr<NGPaintFragment>);
   NGPaintFragment* Last();
   NGPaintFragment* Last(const NGBreakToken&);
+  static scoped_refptr<NGPaintFragment>* Find(scoped_refptr<NGPaintFragment>*,
+                                              const NGBreakToken*);
 
   // The parent NGPaintFragment. This is nullptr for a root; i.e., when parent
   // is not for NGPaint. In the first phase, this means that this is a root of
@@ -245,6 +249,12 @@
   static bool FlippedLocalVisualRectFor(const LayoutObject*, LayoutRect*);
 
  private:
+  static scoped_refptr<NGPaintFragment> CreateOrReuse(
+      scoped_refptr<const NGPhysicalFragment> fragment,
+      NGPhysicalOffset offset,
+      NGPaintFragment* parent,
+      scoped_refptr<NGPaintFragment> previous_instance,
+      bool* populate_children);
   void PopulateDescendants(
       const NGPhysicalOffset inline_offset_to_container_box,
       HashMap<const LayoutObject*, NGPaintFragment*>* last_fragment_map);
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc
index 816f943..3902dd4b 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -163,7 +163,8 @@
       previous_paint_phase_descendant_block_backgrounds_was_empty_(false),
       has_descendant_with_clip_path_(false),
       has_non_isolated_descendant_with_blend_mode_(false),
-      has_descendant_with_sticky_or_fixed_(false),
+      has_fixed_position_descendant_(false),
+      has_sticky_position_descendant_(false),
       has_non_contained_absolute_position_descendant_(false),
       self_painting_status_changed_(false),
       filter_on_effect_node_dirty_(false),
@@ -711,7 +712,8 @@
     has_visible_descendant_ = false;
     has_non_isolated_descendant_with_blend_mode_ = false;
     has_descendant_with_clip_path_ = false;
-    has_descendant_with_sticky_or_fixed_ = false;
+    has_fixed_position_descendant_ = false;
+    has_sticky_position_descendant_ = false;
     has_non_contained_absolute_position_descendant_ = false;
     has_self_painting_layer_descendant_ = false;
     is_non_stacked_with_in_flow_stacked_descendant_ = false;
@@ -740,10 +742,12 @@
       has_descendant_with_clip_path_ |= child->HasDescendantWithClipPath() ||
                                         child->GetLayoutObject().HasClipPath();
 
-      has_descendant_with_sticky_or_fixed_ |=
-          child->HasDescendantWithStickyOrFixed() ||
-          child_style.GetPosition() == EPosition::kSticky ||
+      has_fixed_position_descendant_ |=
+          child->HasFixedPositionDescendant() ||
           child_style.GetPosition() == EPosition::kFixed;
+      has_sticky_position_descendant_ |=
+          child->HasStickyPositionDescendant() ||
+          child_style.GetPosition() == EPosition::kSticky;
 
       if (!can_contain_abs) {
         has_non_contained_absolute_position_descendant_ |=
diff --git a/third_party/blink/renderer/core/paint/paint_layer.h b/third_party/blink/renderer/core/paint/paint_layer.h
index 9bbbd78..982e962 100644
--- a/third_party/blink/renderer/core/paint/paint_layer.h
+++ b/third_party/blink/renderer/core/paint/paint_layer.h
@@ -830,9 +830,13 @@
     DCHECK(!needs_descendant_dependent_flags_update_);
     return has_descendant_with_clip_path_;
   }
-  bool HasDescendantWithStickyOrFixed() const {
+  bool HasFixedPositionDescendant() const {
     DCHECK(!needs_descendant_dependent_flags_update_);
-    return has_descendant_with_sticky_or_fixed_;
+    return has_fixed_position_descendant_;
+  }
+  bool HasStickyPositionDescendant() const {
+    DCHECK(!needs_descendant_dependent_flags_update_);
+    return has_sticky_position_descendant_;
   }
   bool HasNonContainedAbsolutePositionDescendant() const {
     DCHECK(!needs_descendant_dependent_flags_update_);
@@ -1298,7 +1302,8 @@
   // inputs.
   unsigned has_descendant_with_clip_path_ : 1;
   unsigned has_non_isolated_descendant_with_blend_mode_ : 1;
-  unsigned has_descendant_with_sticky_or_fixed_ : 1;
+  unsigned has_fixed_position_descendant_ : 1;
+  unsigned has_sticky_position_descendant_ : 1;
   unsigned has_non_contained_absolute_position_descendant_ : 1;
 
   unsigned self_painting_status_changed_ : 1;
diff --git a/third_party/blink/renderer/core/paint/paint_layer_test.cc b/third_party/blink/renderer/core/paint/paint_layer_test.cc
index efdd0c3..a56863c 100644
--- a/third_party/blink/renderer/core/paint/paint_layer_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_layer_test.cc
@@ -312,7 +312,7 @@
   EXPECT_TRUE(parent->HasVisibleDescendant());
 }
 
-TEST_P(PaintLayerTest, HasDescendantWithSticky) {
+TEST_P(PaintLayerTest, HasStickyPositionDescendant) {
   SetBodyInnerHTML(R"HTML(
     <div id='parent' style='isolation: isolate'>
       <div id='child' style='position: sticky'>
@@ -321,18 +321,18 @@
   )HTML");
   PaintLayer* parent = GetPaintLayerByElementId("parent");
   PaintLayer* child = GetPaintLayerByElementId("child");
-  EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child->HasDescendantWithStickyOrFixed());
+  EXPECT_TRUE(parent->HasStickyPositionDescendant());
+  EXPECT_FALSE(child->HasStickyPositionDescendant());
 
   GetDocument().getElementById("child")->setAttribute(HTMLNames::styleAttr,
                                                       "position: relative");
   GetDocument().View()->UpdateAllLifecyclePhases();
 
-  EXPECT_FALSE(parent->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child->HasDescendantWithStickyOrFixed());
+  EXPECT_FALSE(parent->HasStickyPositionDescendant());
+  EXPECT_FALSE(child->HasStickyPositionDescendant());
 }
 
-TEST_P(PaintLayerTest, HasDescendantWithFixed) {
+TEST_P(PaintLayerTest, HasFixedPositionDescendant) {
   SetBodyInnerHTML(R"HTML(
     <div id='parent' style='isolation: isolate'>
       <div id='child' style='position: fixed'>
@@ -341,18 +341,18 @@
   )HTML");
   PaintLayer* parent = GetPaintLayerByElementId("parent");
   PaintLayer* child = GetPaintLayerByElementId("child");
-  EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child->HasDescendantWithStickyOrFixed());
+  EXPECT_TRUE(parent->HasFixedPositionDescendant());
+  EXPECT_FALSE(child->HasFixedPositionDescendant());
 
   GetDocument().getElementById("child")->setAttribute(HTMLNames::styleAttr,
                                                       "position: relative");
   GetDocument().View()->UpdateAllLifecyclePhases();
 
-  EXPECT_FALSE(parent->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child->HasDescendantWithStickyOrFixed());
+  EXPECT_FALSE(parent->HasFixedPositionDescendant());
+  EXPECT_FALSE(child->HasFixedPositionDescendant());
 }
 
-TEST_P(PaintLayerTest, HasDescendantWithFixedAndSticky) {
+TEST_P(PaintLayerTest, HasFixedAndStickyPositionDescendant) {
   SetBodyInnerHTML(R"HTML(
     <div id='parent' style='isolation: isolate'>
       <div id='child1' style='position: sticky'>
@@ -364,25 +364,34 @@
   PaintLayer* parent = GetPaintLayerByElementId("parent");
   PaintLayer* child1 = GetPaintLayerByElementId("child1");
   PaintLayer* child2 = GetPaintLayerByElementId("child2");
-  EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child1->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child2->HasDescendantWithStickyOrFixed());
+  EXPECT_TRUE(parent->HasFixedPositionDescendant());
+  EXPECT_FALSE(child1->HasFixedPositionDescendant());
+  EXPECT_FALSE(child2->HasFixedPositionDescendant());
+  EXPECT_TRUE(parent->HasStickyPositionDescendant());
+  EXPECT_FALSE(child1->HasStickyPositionDescendant());
+  EXPECT_FALSE(child2->HasStickyPositionDescendant());
 
   GetDocument().getElementById("child1")->setAttribute(HTMLNames::styleAttr,
                                                        "position: relative");
   GetDocument().View()->UpdateAllLifecyclePhases();
 
-  EXPECT_TRUE(parent->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child1->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child2->HasDescendantWithStickyOrFixed());
+  EXPECT_TRUE(parent->HasFixedPositionDescendant());
+  EXPECT_FALSE(child1->HasFixedPositionDescendant());
+  EXPECT_FALSE(child2->HasFixedPositionDescendant());
+  EXPECT_FALSE(parent->HasStickyPositionDescendant());
+  EXPECT_FALSE(child1->HasStickyPositionDescendant());
+  EXPECT_FALSE(child2->HasStickyPositionDescendant());
 
   GetDocument().getElementById("child2")->setAttribute(HTMLNames::styleAttr,
                                                        "position: relative");
   GetDocument().View()->UpdateAllLifecyclePhases();
 
-  EXPECT_FALSE(parent->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child1->HasDescendantWithStickyOrFixed());
-  EXPECT_FALSE(child2->HasDescendantWithStickyOrFixed());
+  EXPECT_FALSE(parent->HasFixedPositionDescendant());
+  EXPECT_FALSE(child1->HasFixedPositionDescendant());
+  EXPECT_FALSE(child2->HasFixedPositionDescendant());
+  EXPECT_FALSE(parent->HasStickyPositionDescendant());
+  EXPECT_FALSE(child1->HasStickyPositionDescendant());
+  EXPECT_FALSE(child2->HasStickyPositionDescendant());
 }
 
 TEST_P(PaintLayerTest, HasNonContainedAbsolutePositionDescendant) {
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 37edff6..1db6d50 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -732,6 +732,32 @@
   return false;
 }
 
+// An effect node can use the current clip as its output clip if the clip won't
+// end before the effect ends. Having explicit output clip can let the later
+// stages use more optimized code path.
+static bool EffectCanUseCurrentClipAsOutputClip(const LayoutObject& object) {
+  DCHECK(NeedsEffect(object));
+
+  if (!object.HasLayer()) {
+    // An SVG object's effect never interleaves with clips.
+    DCHECK(object.IsSVG());
+    return true;
+  }
+
+  const auto* layer = ToLayoutBoxModelObject(object).Layer();
+  // Out-of-flow descendants not contained by this object may escape clips.
+  if (layer->HasNonContainedAbsolutePositionDescendant())
+    return false;
+  if (layer->HasFixedPositionDescendant() &&
+      !object.CanContainFixedPositionObjects())
+    return false;
+  // Some descendants under a pagination container (e.g. composited objects
+  // in SPv1 and column spanners) may escape fragment clips.
+  if (layer->EnclosingPaginationLayer())
+    return false;
+  return true;
+}
+
 void FragmentPaintPropertyTreeBuilder::UpdateEffect() {
   DCHECK(properties_);
   const ComputedStyle& style = object_.StyleRef();
@@ -765,10 +791,9 @@
         clip_path_clip = IntRect();
       }
 
-      // Use the current clip as output_clip for SVG children because their
-      // effects never interleave with clips.
-      const auto* output_clip =
-          object_.IsSVGChild() ? context_.current.clip : nullptr;
+      const auto* output_clip = EffectCanUseCurrentClipAsOutputClip(object_)
+                                    ? context_.current.clip
+                                    : nullptr;
 
       if (mask_clip || clip_path_clip) {
         IntRect combined_clip = mask_clip ? *mask_clip : *clip_path_clip;
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 73c7521..196a6985 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -902,7 +902,8 @@
   const ObjectPaintProperties* node_with_opacity_properties =
       node_with_opacity->FirstFragment().PaintProperties();
   EXPECT_EQ(0.6f, node_with_opacity_properties->Effect()->Opacity());
-  EXPECT_EQ(nullptr, node_with_opacity_properties->Effect()->OutputClip());
+  EXPECT_EQ(DocContentClip(),
+            node_with_opacity_properties->Effect()->OutputClip());
   EXPECT_NE(nullptr, node_with_opacity_properties->Effect()->Parent());
   EXPECT_EQ(nullptr, node_with_opacity_properties->Transform());
   CHECK_EXACT_VISUAL_RECT(LayoutRect(8, 8, 100, 200), node_with_opacity,
@@ -923,7 +924,7 @@
   const ObjectPaintProperties* grand_child_with_opacity_properties =
       grand_child_with_opacity->FirstFragment().PaintProperties();
   EXPECT_EQ(0.4f, grand_child_with_opacity_properties->Effect()->Opacity());
-  EXPECT_EQ(nullptr,
+  EXPECT_EQ(DocContentClip(),
             grand_child_with_opacity_properties->Effect()->OutputClip());
   EXPECT_EQ(node_with_opacity_properties->Effect(),
             grand_child_with_opacity_properties->Effect()->Parent());
@@ -970,7 +971,7 @@
   const ObjectPaintProperties* grand_child_with_opacity_properties =
       grand_child_with_opacity->FirstFragment().PaintProperties();
   EXPECT_EQ(0.4f, grand_child_with_opacity_properties->Effect()->Opacity());
-  EXPECT_EQ(nullptr,
+  EXPECT_EQ(DocContentClip(),
             grand_child_with_opacity_properties->Effect()->OutputClip());
   EXPECT_EQ(node_with_opacity_properties->Effect(),
             grand_child_with_opacity_properties->Effect()->Parent());
@@ -1041,13 +1042,15 @@
   const auto* div_with_opacity_properties =
       PaintPropertiesForElement("divWithOpacity");
   EXPECT_EQ(0.2f, div_with_opacity_properties->Effect()->Opacity());
-  EXPECT_EQ(nullptr, div_with_opacity_properties->Effect()->OutputClip());
+  EXPECT_EQ(DocContentClip(),
+            div_with_opacity_properties->Effect()->OutputClip());
   EXPECT_NE(nullptr, div_with_opacity_properties->Effect()->Parent());
 
   const auto* svg_root_with_opacity_properties =
       PaintPropertiesForElement("svgRootWithOpacity");
   EXPECT_EQ(0.3f, svg_root_with_opacity_properties->Effect()->Opacity());
-  EXPECT_EQ(nullptr, svg_root_with_opacity_properties->Effect()->OutputClip());
+  EXPECT_EQ(DocContentClip(),
+            svg_root_with_opacity_properties->Effect()->OutputClip());
   EXPECT_EQ(div_with_opacity_properties->Effect(),
             svg_root_with_opacity_properties->Effect()->Parent());
 
@@ -1074,7 +1077,8 @@
   const auto* svg_root_with_opacity_properties =
       PaintPropertiesForElement("svgRootWithOpacity");
   EXPECT_EQ(0.3f, svg_root_with_opacity_properties->Effect()->Opacity());
-  EXPECT_EQ(nullptr, svg_root_with_opacity_properties->Effect()->OutputClip());
+  EXPECT_EQ(DocContentClip(),
+            svg_root_with_opacity_properties->Effect()->OutputClip());
   EXPECT_NE(nullptr, svg_root_with_opacity_properties->Effect()->Parent());
 
   const auto* foreign_object_with_opacity_properties =
@@ -1088,7 +1092,8 @@
   const auto* span_with_opacity_properties =
       PaintPropertiesForElement("spanWithOpacity");
   EXPECT_EQ(0.5f, span_with_opacity_properties->Effect()->Opacity());
-  EXPECT_EQ(nullptr, span_with_opacity_properties->Effect()->OutputClip());
+  EXPECT_EQ(svg_root_with_opacity_properties->OverflowClip(),
+            span_with_opacity_properties->Effect()->OutputClip());
   EXPECT_EQ(foreign_object_with_opacity_properties->Effect(),
             span_with_opacity_properties->Effect()->Parent());
 }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
index 1d3af47c..b5389d8 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -1338,4 +1338,33 @@
             gfx::RectF(100, 700, 200, 200));
 }
 
+TEST_P(PaintPropertyTreeUpdateTest,
+       EffectAndClipWithNonContainedOutOfFlowDescendant) {
+  SetBodyInnerHTML(R"HTML(
+    <div id="clip" style="overflow: hidden; width: 100px; height: 100px">
+      <div id="effect" style="opacity: 0.5">
+        <div id="descendant" style="position: fixed">Fixed</div>
+      </div>
+    </div>
+  )HTML");
+
+  const auto* clip_properties = PaintPropertiesForElement("clip");
+  EXPECT_NE(nullptr, clip_properties->OverflowClip());
+  const auto* effect_properties = PaintPropertiesForElement("effect");
+  ASSERT_NE(nullptr, effect_properties->Effect());
+  // The effect's OutputClip is nullptr because of the fixed descendant.
+  EXPECT_EQ(nullptr, effect_properties->Effect()->OutputClip());
+
+  auto* descendant = GetDocument().getElementById("descendant");
+  descendant->setAttribute(HTMLNames::styleAttr, "position: relative");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  EXPECT_EQ(clip_properties->OverflowClip(),
+            effect_properties->Effect()->OutputClip());
+
+  descendant->setAttribute(HTMLNames::styleAttr, "position: absolute");
+  GetDocument().View()->UpdateAllLifecyclePhases();
+  // The effect's OutputClip is nullptr because of the absolute descendant.
+  EXPECT_EQ(nullptr, effect_properties->Effect()->OutputClip());
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/paint/svg_mask_painter.cc b/third_party/blink/renderer/core/paint/svg_mask_painter.cc
index 9e2863a..1920d70 100644
--- a/third_party/blink/renderer/core/paint/svg_mask_painter.cc
+++ b/third_party/blink/renderer/core/paint/svg_mask_painter.cc
@@ -20,12 +20,7 @@
   SECURITY_DCHECK(!mask_.NeedsLayout());
 
   mask_.ClearInvalidationMask();
-
-  FloatRect visual_rect = object.VisualRectInLocalSVGCoordinates();
-  if (visual_rect.IsEmpty() || !mask_.GetElement()->HasChildren())
-    return false;
-
-  return true;
+  return mask_.GetElement()->HasChildren();
 }
 
 void SVGMaskPainter::FinishEffect(const LayoutObject& object,
diff --git a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
index 5241e714..cf2477e 100644
--- a/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
+++ b/third_party/blink/renderer/core/xmlhttprequest/xml_http_request.cc
@@ -746,7 +746,7 @@
 
   if (!async_) {
     if (GetExecutionContext()->IsDocument() &&
-        !GetDocument()->GetFrame()->IsFeatureEnabled(
+        !GetDocument()->GetFrame()->DeprecatedIsFeatureEnabled(
             mojom::FeaturePolicyFeature::kSyncXHR,
             ReportOptions::kReportOnFailure)) {
       LogConsoleError(GetExecutionContext(),
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn
index 90ac2e9..0bd9a1f 100644
--- a/third_party/blink/renderer/modules/BUILD.gn
+++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -143,6 +143,7 @@
     "//third_party/blink/renderer/modules/remoteplayback",
     "//third_party/blink/renderer/modules/screen_orientation",
     "//third_party/blink/renderer/modules/sensor",
+    "//third_party/blink/renderer/modules/serial",
     "//third_party/blink/renderer/modules/service_worker",
     "//third_party/blink/renderer/modules/shapedetection",
     "//third_party/blink/renderer/modules/speech",
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 32aeb52..e9e23221 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
@@ -35,10 +35,8 @@
 #include "third_party/blink/renderer/platform/graphics/test/fake_web_graphics_context_3d_provider.h"
 #include "third_party/blink/renderer/platform/loader/fetch/memory_cache.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
-#include "third_party/skia/include/core/SkColorSpaceXform.h"
 #include "third_party/skia/include/core/SkImage.h"
 #include "third_party/skia/include/core/SkSurface.h"
-#include "third_party/skia/include/core/SkSwizzle.h"
 
 using testing::_;
 using testing::InSequence;
@@ -811,29 +809,6 @@
   Mock::VerifyAndClearExpectations(surface_ptr);
 }
 
-enum class ColorSpaceConversion : uint8_t {
-  NONE = 0,
-  DEFAULT_COLOR_CORRECTED = 1,
-  SRGB = 2,
-  LINEAR_RGB = 3,
-  P3 = 4,
-  REC2020 = 5,
-
-  LAST = REC2020
-};
-
-static ImageBitmapOptions PrepareBitmapOptionsAndSetRuntimeFlags(
-    const ColorSpaceConversion& color_space_conversion) {
-  // Set the color space conversion in ImageBitmapOptions
-  ImageBitmapOptions options;
-  static const Vector<String> kConversions = {
-      "none", "default", "srgb", "linear-rgb", "p3", "rec2020"};
-  options.setColorSpaceConversion(
-      kConversions[static_cast<uint8_t>(color_space_conversion)]);
-
-  return options;
-}
-
 TEST_F(CanvasRenderingContext2DTest, ImageBitmapColorSpaceConversion) {
   Persistent<HTMLCanvasElement> canvas =
       Persistent<HTMLCanvasElement>(CanvasElement());
@@ -845,89 +820,62 @@
   StringOrCanvasGradientOrCanvasPattern fill_style;
   fill_style.SetString("#FFC08040");  // 255,192,128,64
   context->setFillStyle(fill_style);
-  context->fillRect(0, 0, 4, 4);
-  NonThrowableExceptionState exception_state;
-  uint8_t* src_pixel =
-      context->getImageData(2, 2, 1, 1, exception_state)->data()->Data();
+  context->fillRect(0, 0, 1, 1);
+  scoped_refptr<StaticBitmapImage> snapshot =
+      canvas->Snapshot(kFrontBuffer, kPreferNoAcceleration);
+  ASSERT_TRUE(snapshot);
+  sk_sp<SkImage> source_image =
+      snapshot->PaintImageForCurrentFrame().GetSkImage();
+  SkPixmap source_pixmap;
+  source_image->peekPixels(&source_pixmap);
 
   // Create and test the ImageBitmap objects.
-  base::Optional<IntRect> crop_rect = IntRect(0, 0, 4, 4);
-  sk_sp<SkColorSpace> color_space = nullptr;
-  SkColorType color_type = SkColorType::kRGBA_8888_SkColorType;
-  SkColorSpaceXform::ColorFormat color_format32 =
-      SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
-  SkColorSpaceXform::ColorFormat color_format = color_format32;
-  sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB();
-
-  for (uint8_t i =
-           static_cast<uint8_t>(ColorSpaceConversion::DEFAULT_COLOR_CORRECTED);
-       i <= static_cast<uint8_t>(ColorSpaceConversion::LAST); i++) {
-    ColorSpaceConversion color_space_conversion =
-        static_cast<ColorSpaceConversion>(i);
-
-    switch (color_space_conversion) {
-      case ColorSpaceConversion::NONE:
-        NOTREACHED();
-        break;
-      case ColorSpaceConversion::DEFAULT_COLOR_CORRECTED:
-      case ColorSpaceConversion::SRGB:
-        color_space = SkColorSpace::MakeSRGB();
-        color_format = color_format32;
-        break;
-      case ColorSpaceConversion::LINEAR_RGB:
-        color_space = SkColorSpace::MakeSRGBLinear();
-        color_type = SkColorType::kRGBA_F16_SkColorType;
-        color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
-        break;
-      case ColorSpaceConversion::P3:
-        color_space =
-            SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
-                                  SkColorSpace::kDCIP3_D65_Gamut);
-        color_type = SkColorType::kRGBA_F16_SkColorType;
-        color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
-        break;
-      case ColorSpaceConversion::REC2020:
-        color_space =
-            SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
-                                  SkColorSpace::kRec2020_Gamut);
-        color_type = SkColorType::kRGBA_F16_SkColorType;
-        color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
-        break;
-      default:
-        NOTREACHED();
-    }
-
+  base::Optional<IntRect> crop_rect = IntRect(0, 0, 1, 1);
+  for (int conversion_iterator = kColorSpaceConversion_Default;
+       conversion_iterator <= kColorSpaceConversion_Last;
+       conversion_iterator++) {
     // Color convert using ImageBitmap
-    ImageBitmapOptions options =
-        PrepareBitmapOptionsAndSetRuntimeFlags(color_space_conversion);
+    ImageBitmapOptions options;
+    options.setColorSpaceConversion(
+        ColorCorrectionTestUtils::ColorSpaceConversionToString(
+            static_cast<ColorSpaceConversion>(conversion_iterator)));
     ImageBitmap* image_bitmap = ImageBitmap::Create(canvas, crop_rect, options);
     ASSERT_TRUE(image_bitmap);
     sk_sp<SkImage> converted_image =
         image_bitmap->BitmapImage()->PaintImageForCurrentFrame().GetSkImage();
     ASSERT_TRUE(converted_image);
-    SkImageInfo image_info =
-        SkImageInfo::Make(1, 1, color_type, SkAlphaType::kUnpremul_SkAlphaType,
-                          converted_image->refColorSpace());
-    std::unique_ptr<uint8_t[]> converted_pixel(
-        new uint8_t[image_info.bytesPerPixel()]());
-    EXPECT_TRUE(converted_image->readPixels(image_info, converted_pixel.get(),
-                                            image_info.minRowBytes(), 2, 2));
+    SkPixmap converted_pixmap;
+    converted_image->peekPixels(&converted_pixmap);
 
-    // Transform the source pixel and check if the image bitmap color conversion
-    // is done correctly.
-    std::unique_ptr<SkColorSpaceXform> color_space_xform =
-        SkColorSpaceXform::New(src_rgb_color_space.get(), color_space.get());
-    std::unique_ptr<uint8_t[]> transformed_pixel(
-        new uint8_t[image_info.bytesPerPixel()]());
-    EXPECT_TRUE(color_space_xform->apply(color_format, transformed_pixel.get(),
-                                         color_format32, src_pixel, 1,
-                                         SkAlphaType::kUnpremul_SkAlphaType));
+    // Manual color convert for testing
+    sk_sp<SkColorSpace> color_space =
+        ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace(
+            static_cast<ColorSpaceConversion>(conversion_iterator));
+    if (conversion_iterator == kColorSpaceConversion_Preserve)
+      color_space = SkColorSpace::MakeSRGB();
+
+    // TODO: crbug.com/768855: Remove if statement when CanvasResourceProvider
+    // does not use SkColorSpaceXformCanvas (which rips off sRGB from
+    // ImageBitmap).
+    if (!color_space->isSRGB()) {
+      EXPECT_TRUE(SkColorSpace::Equals(color_space.get(),
+                                       converted_image->colorSpace()));
+    }
+
+    SkColorType color_type = SkColorType::kN32_SkColorType;
+    if (color_space && color_space->gammaIsLinear())
+      color_type = kRGBA_F16_SkColorType;
+    SkImageInfo image_info = SkImageInfo::Make(
+        1, 1, color_type, SkAlphaType::kPremul_SkAlphaType, color_space);
+    SkBitmap manual_converted_bitmap;
+    EXPECT_TRUE(manual_converted_bitmap.tryAllocPixels(image_info));
+    source_pixmap.readPixels(manual_converted_bitmap.pixmap(), 0, 0);
 
     ColorCorrectionTestUtils::CompareColorCorrectedPixels(
-        converted_pixel.get(), transformed_pixel.get(), 1,
-        (color_type == kRGBA_8888_SkColorType) ? kPixelFormat_8888
-                                               : kPixelFormat_hhhh,
-        kAlphaUnmultiplied, kUnpremulRoundTripTolerance);
+        converted_pixmap.addr(), manual_converted_bitmap.pixmap().addr(), 1,
+        (color_type == kN32_SkColorType) ? kPixelFormat_8888
+                                         : kPixelFormat_hhhh,
+        kAlphaMultiplied, kNoUnpremulRoundTripTolerance);
   }
 }
 
diff --git a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
index 22e969f3..6bdb1ba 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
+++ b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -303,7 +303,7 @@
   Document* document = ToDocument(execution_context);
 
   if (!document->GetFrame() ||
-      !document->GetFrame()->IsFeatureEnabled(
+      !document->GetFrame()->DeprecatedIsFeatureEnabled(
           mojom::FeaturePolicyFeature::kEncryptedMedia)) {
     UseCounter::Count(document,
                       WebFeature::kEncryptedMediaDisabledByFeaturePolicy);
diff --git a/third_party/blink/renderer/modules/event_target_modules_names.json5 b/third_party/blink/renderer/modules/event_target_modules_names.json5
index 38ae796..433fd83 100644
--- a/third_party/blink/renderer/modules/event_target_modules_names.json5
+++ b/third_party/blink/renderer/modules/event_target_modules_names.json5
@@ -41,6 +41,7 @@
     "modules/remoteplayback/RemotePlayback",
     "modules/screen_orientation/ScreenOrientation",
     "modules/sensor/Sensor",
+    "modules/serial/Serial",
     "modules/service_worker/ServiceWorker",
     "modules/service_worker/ServiceWorkerContainer",
     "modules/service_worker/ServiceWorkerGlobalScope",
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_system.cc b/third_party/blink/renderer/modules/filesystem/dom_file_system.cc
index 34cd458..9d079872 100644
--- a/third_party/blink/renderer/modules/filesystem/dom_file_system.cc
+++ b/third_party/blink/renderer/modules/filesystem/dom_file_system.cc
@@ -33,7 +33,6 @@
 #include <memory>
 
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_file_system.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/renderer/core/probe/core_probes.h"
 #include "third_party/blink/renderer/modules/filesystem/directory_entry.h"
@@ -150,7 +149,7 @@
   std::unique_ptr<AsyncFileSystemCallbacks> callbacks =
       FileWriterCallbacks::Create(file_writer, success_callback, error_callback,
                                   context_);
-  FileSystemDispatcher::GetThreadSpecificInstance().InitializeFileWriter(
+  FileSystemDispatcher::From(context_).InitializeFileWriter(
       CreateFileSystemURL(file_entry), std::move(callbacks));
 }
 
@@ -160,7 +159,7 @@
     ErrorCallbackBase* error_callback) {
   KURL file_system_url = CreateFileSystemURL(file_entry);
 
-  FileSystemDispatcher::GetThreadSpecificInstance().CreateSnapshotFile(
+  FileSystemDispatcher::From(context_).CreateSnapshotFile(
       file_system_url,
       SnapshotFileCallback::Create(this, file_entry->name(), file_system_url,
                                    success_callback, error_callback, context_));
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc b/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc
index 0dc350b..98e1a65 100644
--- a/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc
+++ b/third_party/blink/renderer/modules/filesystem/dom_file_system_base.cc
@@ -32,7 +32,6 @@
 
 #include <memory>
 #include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_file_system.h"
 #include "third_party/blink/public/platform/web_security_origin.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/fileapi/file.h"
@@ -73,13 +72,6 @@
   ScriptWrappable::Trace(visitor);
 }
 
-WebFileSystem* DOMFileSystemBase::FileSystem() const {
-  Platform* platform = Platform::Current();
-  if (!platform)
-    return nullptr;
-  return platform->FileSystem();
-}
-
 const SecurityOrigin* DOMFileSystemBase::GetSecurityOrigin() const {
   return context_->GetSecurityOrigin();
 }
@@ -219,8 +211,7 @@
     SynchronousType synchronous_type) {
   std::unique_ptr<AsyncFileSystemCallbacks> callbacks(MetadataCallbacks::Create(
       success_callback, error_callback, context_, this));
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_);
 
   if (synchronous_type == kSynchronous) {
     dispatcher.ReadMetadataSync(CreateFileSystemURL(entry),
@@ -285,8 +276,7 @@
       success_callback, error_callback, context_, parent->filesystem(),
       destination_path, source->isDirectory()));
 
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_);
   const KURL& src = CreateFileSystemURL(source);
   const KURL& dest =
       parent->filesystem()->CreateFileSystemURL(destination_path);
@@ -317,8 +307,7 @@
   const KURL& src = CreateFileSystemURL(source);
   const KURL& dest =
       parent->filesystem()->CreateFileSystemURL(destination_path);
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_);
   if (synchronous_type == kSynchronous)
     dispatcher.CopySync(src, dest, std::move(callbacks));
   else
@@ -340,8 +329,7 @@
   std::unique_ptr<AsyncFileSystemCallbacks> callbacks(
       VoidCallbacks::Create(success_callback, error_callback, context_, this));
   const KURL& url = CreateFileSystemURL(entry);
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_);
   if (synchronous_type == kSynchronous)
     dispatcher.RemoveSync(url, /*recursive=*/false, std::move(callbacks));
   else
@@ -364,8 +352,7 @@
   std::unique_ptr<AsyncFileSystemCallbacks> callbacks(
       VoidCallbacks::Create(success_callback, error_callback, context_, this));
   const KURL& url = CreateFileSystemURL(entry);
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_);
   if (synchronous_type == kSynchronous)
     dispatcher.RemoveSync(url, /*recursive=*/true, std::move(callbacks));
   else
@@ -379,7 +366,7 @@
   DCHECK(entry);
   String path = DOMFilePath::GetDirectory(entry->fullPath());
 
-  FileSystemDispatcher::GetThreadSpecificInstance().Exists(
+  FileSystemDispatcher::From(context_).Exists(
       CreateFileSystemURL(path), /*is_directory=*/true,
       EntryCallbacks::Create(success_callback, error_callback, context_, this,
                              path, true));
@@ -401,8 +388,7 @@
   std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::Create(
       success_callback, error_callback, context_, this, absolute_path, false));
   const KURL& url = CreateFileSystemURL(absolute_path);
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_);
 
   if (flags.createFlag()) {
     if (synchronous_type == kSynchronous)
@@ -434,8 +420,7 @@
   std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::Create(
       success_callback, error_callback, context_, this, absolute_path, true));
   const KURL& url = CreateFileSystemURL(absolute_path);
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_);
 
   if (flags.createFlag()) {
     if (synchronous_type == kSynchronous) {
@@ -464,8 +449,7 @@
 
   std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntriesCallbacks::Create(
       success_callback, error_callback, context_, reader, path));
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context_);
   const KURL& url = CreateFileSystemURL(path);
   if (synchronous_type == kSynchronous) {
     dispatcher.ReadDirectorySync(url, std::move(callbacks));
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h b/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h
index 643929f..83452e2 100644
--- a/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h
+++ b/third_party/blink/renderer/modules/filesystem/dom_file_system_base.h
@@ -42,10 +42,6 @@
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
 namespace blink {
-class WebFileSystem;
-}  // namespace blink
-
-namespace blink {
 
 class DirectoryReaderBase;
 class EntryBase;
@@ -83,7 +79,6 @@
   const String& name() const { return name_; }
   mojom::blink::FileSystemType GetType() const { return type_; }
   KURL RootURL() const { return filesystem_root_url_; }
-  WebFileSystem* FileSystem() const;
   const SecurityOrigin* GetSecurityOrigin() const;
 
   // The clonable flag is used in the structured clone algorithm to test
diff --git a/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc b/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc
index 08b3747..1d1b6e1 100644
--- a/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc
+++ b/third_party/blink/renderer/modules/filesystem/dom_file_system_sync.cc
@@ -33,7 +33,6 @@
 #include <memory>
 
 #include "base/memory/ptr_util.h"
-#include "third_party/blink/public/platform/web_file_system.h"
 #include "third_party/blink/renderer/core/fileapi/file.h"
 #include "third_party/blink/renderer/core/fileapi/file_error.h"
 #include "third_party/blink/renderer/modules/filesystem/directory_entry_sync.h"
@@ -140,7 +139,7 @@
   KURL file_system_url = CreateFileSystemURL(file_entry);
   CreateFileHelper::CreateFileResult* result(
       CreateFileHelper::CreateFileResult::Create());
-  FileSystemDispatcher::GetThreadSpecificInstance().CreateSnapshotFileSync(
+  FileSystemDispatcher::From(context_).CreateSnapshotFileSync(
       file_system_url, CreateFileHelper::Create(result, file_entry->name(),
                                                 file_system_url, GetType()));
   if (result->failed_) {
@@ -157,7 +156,7 @@
     ExceptionState& exception_state) {
   DCHECK(file_entry);
 
-  FileWriterSync* file_writer = FileWriterSync::Create();
+  FileWriterSync* file_writer = FileWriterSync::Create(context_);
 
   FileWriterCallbacksSyncHelper* sync_helper =
       FileWriterCallbacksSyncHelper::Create();
@@ -166,7 +165,7 @@
                                   sync_helper->GetSuccessCallback(),
                                   sync_helper->GetErrorCallback(), context_);
 
-  FileSystemDispatcher::GetThreadSpecificInstance().InitializeFileWriterSync(
+  FileSystemDispatcher::From(context_).InitializeFileWriterSync(
       CreateFileSystemURL(file_entry), std::move(callbacks));
 
   FileWriterBase* success = sync_helper->GetResultOrThrow(exception_state);
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
index 1130460b..ec80085 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
+++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.cc
@@ -5,9 +5,10 @@
 #include "third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h"
 
 #include "build/build_config.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/platform/file_path_conversion.h"
-#include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
@@ -68,23 +69,34 @@
   std::unique_ptr<AsyncFileSystemCallbacks> callbacks_;
 };
 
-FileSystemDispatcher::FileSystemDispatcher() : next_operation_id_(1) {}
+FileSystemDispatcher::FileSystemDispatcher(ExecutionContext& context)
+    : Supplement<ExecutionContext>(context), next_operation_id_(1) {}
 
 // static
-FileSystemDispatcher& FileSystemDispatcher::GetThreadSpecificInstance() {
-  DEFINE_THREAD_SAFE_STATIC_LOCAL(ThreadSpecific<FileSystemDispatcher>,
-                                  file_system_dispatcher, ());
-  return *file_system_dispatcher;
+const char FileSystemDispatcher::kSupplementName[] = "FileSystemDispatcher";
+
+// static
+FileSystemDispatcher& FileSystemDispatcher::From(ExecutionContext* context) {
+  DCHECK(context);
+  FileSystemDispatcher* dispatcher =
+      Supplement<ExecutionContext>::From<FileSystemDispatcher>(context);
+  if (!dispatcher) {
+    dispatcher = new FileSystemDispatcher(*context);
+    Supplement<ExecutionContext>::ProvideTo(*context, dispatcher);
+  }
+  return *dispatcher;
 }
 
+FileSystemDispatcher::~FileSystemDispatcher() = default;
+
 void FileSystemDispatcher::OpenFileSystem(
     const KURL& origin_url,
     mojom::blink::FileSystemType type,
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().Open(
       origin_url, type,
-      WTF::Bind(&FileSystemDispatcher::DidOpenFileSystem, WTF::Unretained(this),
-                std::move(callbacks)));
+      WTF::Bind(&FileSystemDispatcher::DidOpenFileSystem,
+                WrapWeakPersistent(this), std::move(callbacks)));
 }
 
 void FileSystemDispatcher::OpenFileSystemSync(
@@ -103,8 +115,9 @@
     const KURL& filesystem_url,
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().ResolveURL(
-      filesystem_url, WTF::Bind(&FileSystemDispatcher::DidResolveURL,
-                                WTF::Unretained(this), std::move(callbacks)));
+      filesystem_url,
+      WTF::Bind(&FileSystemDispatcher::DidResolveURL, WrapWeakPersistent(this),
+                std::move(callbacks)));
 }
 
 void FileSystemDispatcher::ResolveURLSync(
@@ -126,7 +139,7 @@
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().Move(
       src_path, dest_path,
-      WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this),
+      WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this),
                 std::move(callbacks)));
 }
 
@@ -145,7 +158,7 @@
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().Copy(
       src_path, dest_path,
-      WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this),
+      WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this),
                 std::move(callbacks)));
 }
 
@@ -164,7 +177,7 @@
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().Remove(
       path, recursive,
-      WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this),
+      WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this),
                 std::move(callbacks)));
 }
 
@@ -182,7 +195,7 @@
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().ReadMetadata(
       path, WTF::Bind(&FileSystemDispatcher::DidReadMetadata,
-                      WTF::Unretained(this), std::move(callbacks)));
+                      WrapWeakPersistent(this), std::move(callbacks)));
 }
 
 void FileSystemDispatcher::ReadMetadataSync(
@@ -200,7 +213,7 @@
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().Create(
       path, exclusive, /*is_directory=*/false, /*is_recursive=*/false,
-      WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this),
+      WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this),
                 std::move(callbacks)));
 }
 
@@ -221,7 +234,7 @@
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().Create(
       path, exclusive, /*is_directory=*/true, recursive,
-      WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this),
+      WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this),
                 std::move(callbacks)));
 }
 
@@ -242,7 +255,7 @@
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().Exists(
       path, is_directory,
-      WTF::Bind(&FileSystemDispatcher::DidFinish, WTF::Unretained(this),
+      WTF::Bind(&FileSystemDispatcher::DidFinish, WrapWeakPersistent(this),
                 std::move(callbacks)));
 }
 
@@ -284,7 +297,7 @@
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().ReadMetadata(
       path, WTF::Bind(&FileSystemDispatcher::InitializeFileWriterCallback,
-                      WTF::Unretained(this), path, std::move(callbacks)));
+                      WrapWeakPersistent(this), path, std::move(callbacks)));
 }
 
 void FileSystemDispatcher::InitializeFileWriterSync(
@@ -307,11 +320,11 @@
   int operation_id = next_operation_id_++;
   op_ptr.set_connection_error_handler(
       WTF::Bind(&FileSystemDispatcher::RemoveOperationPtr,
-                WTF::Unretained(this), operation_id));
+                WrapWeakPersistent(this), operation_id));
   cancellable_operations_.insert(operation_id, std::move(op_ptr));
   GetFileSystemManager().Truncate(
       path, offset, std::move(op_request),
-      WTF::Bind(&FileSystemDispatcher::DidTruncate, WTF::Unretained(this),
+      WTF::Bind(&FileSystemDispatcher::DidTruncate, WrapWeakPersistent(this),
                 operation_id, std::move(callback)));
 
   if (request_id_out)
@@ -338,7 +351,7 @@
   int operation_id = next_operation_id_++;
   op_ptr.set_connection_error_handler(
       WTF::Bind(&FileSystemDispatcher::RemoveOperationPtr,
-                WTF::Unretained(this), operation_id));
+                WrapWeakPersistent(this), operation_id));
   cancellable_operations_.insert(operation_id, std::move(op_ptr));
 
   mojom::blink::FileSystemOperationListenerPtr listener_ptr;
@@ -379,7 +392,7 @@
   }
   cancellable_operations_.find(request_id_to_cancel)
       ->value->Cancel(WTF::Bind(&FileSystemDispatcher::DidCancel,
-                                WTF::Unretained(this), std::move(callback),
+                                WrapWeakPersistent(this), std::move(callback),
                                 request_id_to_cancel));
 }
 
@@ -388,7 +401,7 @@
     std::unique_ptr<AsyncFileSystemCallbacks> callbacks) {
   GetFileSystemManager().CreateSnapshotFile(
       file_path, WTF::Bind(&FileSystemDispatcher::DidCreateSnapshotFile,
-                           WTF::Unretained(this), std::move(callbacks)));
+                           WrapWeakPersistent(this), std::move(callbacks)));
 }
 
 void FileSystemDispatcher::CreateSnapshotFileSync(
@@ -422,9 +435,24 @@
           std::move(callbacks)));
 }
 
+void FileSystemDispatcher::ChooseEntry(
+    std::unique_ptr<ChooseEntryCallbacks> callbacks) {
+  GetFileSystemManager().ChooseEntry(WTF::Bind(
+      [](std::unique_ptr<ChooseEntryCallbacks> callbacks,
+         base::File::Error result,
+         Vector<mojom::blink::FileSystemEntryPtr> entries) {
+        if (result != base::File::FILE_OK) {
+          callbacks->OnError(result);
+        } else {
+          callbacks->OnSuccess(std::move(entries));
+        }
+      },
+      std::move(callbacks)));
+}
+
 mojom::blink::FileSystemManager& FileSystemDispatcher::GetFileSystemManager() {
   if (!file_system_manager_ptr_) {
-    Platform::Current()->GetInterfaceProvider()->GetInterface(
+    GetSupplementable()->GetInterfaceProvider()->GetInterface(
         mojo::MakeRequest(&file_system_manager_ptr_));
   }
   return *file_system_manager_ptr_;
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
index 2b3b33a..d8a899a 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
+++ b/third_party/blink/renderer/modules/filesystem/file_system_dispatcher.h
@@ -10,6 +10,7 @@
 #include "third_party/blink/public/platform/web_callbacks.h"
 #include "third_party/blink/renderer/platform/async_file_system_callbacks.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
 
 namespace WTF {
 class String;
@@ -18,18 +19,25 @@
 namespace blink {
 
 class KURL;
+class ExecutionContext;
 
 // Sends messages via mojo to the blink::mojom::FileSystemManager service
-// running in the browser process. It is currently created and stored in a
-// thread local variable. A thread specific instance can be obtained using
-// GetThreadSpecificInstance().
-class FileSystemDispatcher {
+// running in the browser process. It is owned by ExecutionContext, and
+// instances are created lazily by calling FileSystemDispatcher::From().
+class FileSystemDispatcher
+    : public GarbageCollectedFinalized<FileSystemDispatcher>,
+      public Supplement<ExecutionContext> {
+  USING_GARBAGE_COLLECTED_MIXIN(FileSystemDispatcher);
+
  public:
   using StatusCallback = base::OnceCallback<void(base::File::Error error)>;
   using WriteCallback =
       base::RepeatingCallback<void(int64_t bytes, bool complete)>;
 
-  static FileSystemDispatcher& GetThreadSpecificInstance();
+  static const char kSupplementName[];
+
+  static FileSystemDispatcher& From(ExecutionContext* context);
+  virtual ~FileSystemDispatcher();
 
   void OpenFileSystem(const KURL& url,
                       mojom::blink::FileSystemType type,
@@ -133,12 +141,15 @@
   void CreateFileWriter(const KURL& file_path,
                         std::unique_ptr<CreateFileWriterCallbacks>);
 
+  using ChooseEntryCallbacks =
+      WebCallbacks<Vector<mojom::blink::FileSystemEntryPtr>, base::File::Error>;
+  void ChooseEntry(std::unique_ptr<ChooseEntryCallbacks> callbacks);
+
  private:
   class WriteListener;
   class ReadDirectoryListener;
-  friend class WTF::ThreadSpecific<FileSystemDispatcher>;
 
-  FileSystemDispatcher();
+  explicit FileSystemDispatcher(ExecutionContext& context);
 
   mojom::blink::FileSystemManager& GetFileSystemManager();
 
diff --git a/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc b/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc
index 5775e5c..2b66212 100644
--- a/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc
+++ b/third_party/blink/renderer/modules/filesystem/file_system_file_handle.cc
@@ -60,9 +60,9 @@
 ScriptPromise FileSystemFileHandle::createWriter(ScriptState* script_state) {
   auto* resolver = ScriptPromiseResolver::Create(script_state);
   ScriptPromise result = resolver->Promise();
-  FileSystemDispatcher::GetThreadSpecificInstance().CreateFileWriter(
-      filesystem()->CreateFileSystemURL(this),
-      std::make_unique<CreateWriterCallbacks>(resolver));
+  FileSystemDispatcher::From(ExecutionContext::From(script_state))
+      .CreateFileWriter(filesystem()->CreateFileSystemURL(this),
+                        std::make_unique<CreateWriterCallbacks>(resolver));
   return result;
 }
 
@@ -70,12 +70,13 @@
   auto* resolver = ScriptPromiseResolver::Create(script_state);
   ScriptPromise result = resolver->Promise();
   KURL file_system_url = filesystem()->CreateFileSystemURL(this);
-  FileSystemDispatcher::GetThreadSpecificInstance().CreateSnapshotFile(
-      file_system_url,
-      SnapshotFileCallback::Create(filesystem(), name(), file_system_url,
-                                   new OnDidCreateSnapshotFilePromise(resolver),
-                                   new PromiseErrorCallback(resolver),
-                                   ExecutionContext::From(script_state)));
+  FileSystemDispatcher::From(ExecutionContext::From(script_state))
+      .CreateSnapshotFile(file_system_url,
+                          SnapshotFileCallback::Create(
+                              filesystem(), name(), file_system_url,
+                              new OnDidCreateSnapshotFilePromise(resolver),
+                              new PromiseErrorCallback(resolver),
+                              ExecutionContext::From(script_state)));
   return result;
 }
 
diff --git a/third_party/blink/renderer/modules/filesystem/file_writer.cc b/third_party/blink/renderer/modules/filesystem/file_writer.cc
index 56e910f..427f69d 100644
--- a/third_party/blink/renderer/modules/filesystem/file_writer.cc
+++ b/third_party/blink/renderer/modules/filesystem/file_writer.cc
@@ -225,23 +225,25 @@
 }
 
 void FileWriter::DoTruncate(const KURL& path, int64_t offset) {
-  FileSystemDispatcher::GetThreadSpecificInstance().Truncate(
-      path, offset, &request_id_,
-      WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this)));
+  FileSystemDispatcher::From(GetExecutionContext())
+      .Truncate(path, offset, &request_id_,
+                WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this)));
 }
 
 void FileWriter::DoWrite(const KURL& path,
                          const String& blob_id,
                          int64_t offset) {
-  FileSystemDispatcher::GetThreadSpecificInstance().Write(
-      path, blob_id, offset, &request_id_,
-      WTF::BindRepeating(&FileWriter::DidWrite, WrapWeakPersistent(this)),
-      WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this)));
+  FileSystemDispatcher::From(GetExecutionContext())
+      .Write(
+          path, blob_id, offset, &request_id_,
+          WTF::BindRepeating(&FileWriter::DidWrite, WrapWeakPersistent(this)),
+          WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this)));
 }
 
 void FileWriter::DoCancel() {
-  FileSystemDispatcher::GetThreadSpecificInstance().Cancel(
-      request_id_, WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this)));
+  FileSystemDispatcher::From(GetExecutionContext())
+      .Cancel(request_id_,
+              WTF::Bind(&FileWriter::DidFinish, WrapWeakPersistent(this)));
 }
 
 void FileWriter::CompleteAbort() {
@@ -328,6 +330,8 @@
     DoOperation(kOperationAbort);
     ready_state_ = kDone;
   }
+  // Prevents any queued operations from running after abort completes.
+  queued_operation_ = kOperationNone;
 }
 
 void FileWriter::Trace(blink::Visitor* visitor) {
diff --git a/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc b/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc
index 3242da55..e9c20b16 100644
--- a/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc
+++ b/third_party/blink/renderer/modules/filesystem/file_writer_sync.cc
@@ -98,26 +98,33 @@
 }
 
 void FileWriterSync::DoTruncate(const KURL& path, int64_t offset) {
-  FileSystemDispatcher::GetThreadSpecificInstance().TruncateSync(
-      path, offset,
-      WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this)));
+  if (!GetExecutionContext())
+    return;
+  FileSystemDispatcher::From(GetExecutionContext())
+      .TruncateSync(
+          path, offset,
+          WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this)));
 }
 
 void FileWriterSync::DoWrite(const KURL& path,
                              const String& blob_id,
                              int64_t offset) {
-  FileSystemDispatcher::GetThreadSpecificInstance().WriteSync(
-      path, blob_id, offset,
-      WTF::BindRepeating(&FileWriterSync::DidWrite, WrapWeakPersistent(this)),
-      WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this)));
+  if (!GetExecutionContext())
+    return;
+  FileSystemDispatcher::From(GetExecutionContext())
+      .WriteSync(
+          path, blob_id, offset,
+          WTF::BindRepeating(&FileWriterSync::DidWrite,
+                             WrapWeakPersistent(this)),
+          WTF::Bind(&FileWriterSync::DidFinish, WrapWeakPersistent(this)));
 }
 
 void FileWriterSync::DoCancel() {
   NOTREACHED();
 }
 
-FileWriterSync::FileWriterSync()
-    : error_(base::File::FILE_OK), complete_(true) {}
+FileWriterSync::FileWriterSync(ExecutionContext* context)
+    : ContextClient(context), error_(base::File::FILE_OK), complete_(true) {}
 
 void FileWriterSync::PrepareForWrite() {
   DCHECK(complete_);
@@ -130,6 +137,7 @@
 void FileWriterSync::Trace(blink::Visitor* visitor) {
   ScriptWrappable::Trace(visitor);
   FileWriterBase::Trace(visitor);
+  ContextClient::Trace(visitor);
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/filesystem/file_writer_sync.h b/third_party/blink/renderer/modules/filesystem/file_writer_sync.h
index 4a8002a..6561606 100644
--- a/third_party/blink/renderer/modules/filesystem/file_writer_sync.h
+++ b/third_party/blink/renderer/modules/filesystem/file_writer_sync.h
@@ -31,6 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_WRITER_SYNC_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_FILESYSTEM_FILE_WRITER_SYNC_H_
 
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/core/fileapi/file_error.h"
 #include "third_party/blink/renderer/modules/filesystem/file_writer_base.h"
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
@@ -41,12 +42,16 @@
 class Blob;
 class ExceptionState;
 
-class FileWriterSync final : public ScriptWrappable, public FileWriterBase {
+class FileWriterSync final : public ScriptWrappable,
+                             public FileWriterBase,
+                             public ContextClient {
   DEFINE_WRAPPERTYPEINFO();
   USING_GARBAGE_COLLECTED_MIXIN(FileWriterSync);
 
  public:
-  static FileWriterSync* Create() { return new FileWriterSync(); }
+  static FileWriterSync* Create(ExecutionContext* context) {
+    return new FileWriterSync(context);
+  }
   ~FileWriterSync() override;
   void Trace(blink::Visitor*) override;
 
@@ -65,7 +70,7 @@
   void DoCancel() override;
 
  private:
-  FileWriterSync();
+  explicit FileWriterSync(ExecutionContext* context);
   void PrepareForWrite();
 
   base::File::Error error_;
diff --git a/third_party/blink/renderer/modules/filesystem/local_file_system.cc b/third_party/blink/renderer/modules/filesystem/local_file_system.cc
index 0a7e003..29c34b3 100644
--- a/third_party/blink/renderer/modules/filesystem/local_file_system.cc
+++ b/third_party/blink/renderer/modules/filesystem/local_file_system.cc
@@ -35,7 +35,6 @@
 #include "third_party/blink/public/common/features.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/public/platform/web_file_system.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
@@ -116,12 +115,14 @@
 
 namespace {
 
-class ChooseEntryCallbacks : public WebFileSystem::ChooseEntryCallbacks {
+class ChooseEntryCallbacks
+    : public WebCallbacks<Vector<mojom::blink::FileSystemEntryPtr>,
+                          base::File::Error> {
  public:
   ChooseEntryCallbacks(ScriptPromiseResolver* resolver, bool return_multiple)
       : resolver_(resolver), return_multiple_(return_multiple) {}
 
-  void OnSuccess(WebVector<WebFileSystem::FileSystemEntry> entries) override {
+  void OnSuccess(Vector<mojom::blink::FileSystemEntryPtr> entries) override {
     ScriptState::Scope scope(resolver_->GetScriptState());
     if (return_multiple_) {
       Vector<ScriptPromise> result;
@@ -141,15 +142,16 @@
   }
 
  private:
-  ScriptPromise CreateFileHandle(const WebFileSystem::FileSystemEntry& entry) {
+  ScriptPromise CreateFileHandle(
+      const mojom::blink::FileSystemEntryPtr& entry) {
     auto* new_resolver =
         ScriptPromiseResolver::Create(resolver_->GetScriptState());
     ScriptPromise result = new_resolver->Promise();
     auto* fs = DOMFileSystem::CreateIsolatedFileSystem(
-        resolver_->GetExecutionContext(), entry.file_system_id);
+        resolver_->GetExecutionContext(), entry->file_system_id);
     // TODO(mek): Try to create handle directly rather than having to do more
     // IPCs to get the actual entries.
-    fs->GetFile(fs->root(), entry.base_name, FileSystemFlags(),
+    fs->GetFile(fs->root(), entry->base_name, FileSystemFlags(),
                 new EntryCallbacks::OnDidGetEntryPromiseImpl(new_resolver),
                 new PromiseErrorCallback(new_resolver));
     return result;
@@ -168,24 +170,8 @@
     return;
   }
 
-  WebFileSystem* file_system = GetFileSystem();
-  if (!file_system) {
-    resolver->Reject(
-        FileError::CreateDOMException(base::File::FILE_ERROR_ABORT));
-    return;
-  }
-
-  file_system->ChooseEntry(
-      Supplement<LocalFrame>::GetSupplementable()->Client()->GetWebFrame(),
-      std::make_unique<ChooseEntryCallbacks>(resolver, false));
-}
-
-WebFileSystem* LocalFileSystem::GetFileSystem() const {
-  Platform* platform = Platform::Current();
-  if (!platform)
-    return nullptr;
-
-  return platform->FileSystem();
+  FileSystemDispatcher::From(resolver->GetExecutionContext())
+      .ChooseEntry(std::make_unique<ChooseEntryCallbacks>(resolver, false));
 }
 
 void LocalFileSystem::RequestFileSystemAccessInternal(
@@ -230,8 +216,7 @@
       KURL(NullURL(), context->GetSecurityOrigin()->ToString());
   std::unique_ptr<AsyncFileSystemCallbacks> async_callbacks =
       callbacks->Release();
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context);
   if (sync_type == kSynchronous) {
     dispatcher.OpenFileSystemSync(storage_partition, type,
                                   std::move(async_callbacks));
@@ -245,8 +230,7 @@
                                          const KURL& file_system_url,
                                          CallbackWrapper* callbacks,
                                          SynchronousType sync_type) {
-  FileSystemDispatcher& dispatcher =
-      FileSystemDispatcher::GetThreadSpecificInstance();
+  FileSystemDispatcher& dispatcher = FileSystemDispatcher::From(context);
   std::unique_ptr<AsyncFileSystemCallbacks> async_callbacks =
       callbacks->Release();
   if (sync_type == kSynchronous) {
diff --git a/third_party/blink/renderer/modules/filesystem/local_file_system.h b/third_party/blink/renderer/modules/filesystem/local_file_system.h
index b3e2823b..b137d0e9 100644
--- a/third_party/blink/renderer/modules/filesystem/local_file_system.h
+++ b/third_party/blink/renderer/modules/filesystem/local_file_system.h
@@ -49,7 +49,6 @@
 class ExecutionContext;
 class KURL;
 class ScriptPromiseResolver;
-class WebFileSystem;
 
 class LocalFileSystem final : public GarbageCollectedFinalized<LocalFileSystem>,
                               public Supplement<LocalFrame>,
@@ -87,7 +86,6 @@
   const char* NameInHeapSnapshot() const override { return "LocalFileSystem"; }
 
  private:
-  WebFileSystem* GetFileSystem() const;
   void FileSystemNotAvailable(ExecutionContext*, CallbackWrapper*);
 
   void RequestFileSystemAccessInternal(ExecutionContext*,
diff --git a/third_party/blink/renderer/modules/geolocation/geolocation.cc b/third_party/blink/renderer/modules/geolocation/geolocation.cc
index b5b0363..c0eda1e 100644
--- a/third_party/blink/renderer/modules/geolocation/geolocation.cc
+++ b/third_party/blink/renderer/modules/geolocation/geolocation.cc
@@ -224,8 +224,9 @@
     return;
   }
 
-  if (!GetFrame()->IsFeatureEnabled(mojom::FeaturePolicyFeature::kGeolocation,
-                                    ReportOptions::kReportOnFailure)) {
+  if (!GetFrame()->DeprecatedIsFeatureEnabled(
+          mojom::FeaturePolicyFeature::kGeolocation,
+          ReportOptions::kReportOnFailure)) {
     UseCounter::Count(GetDocument(),
                       WebFeature::kGeolocationDisabledByFeaturePolicy);
     GetDocument()->AddConsoleMessage(ConsoleMessage::Create(
diff --git a/third_party/blink/renderer/modules/mediastream/user_media_request.cc b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
index 64361af..09a493d 100644
--- a/third_party/blink/renderer/modules/mediastream/user_media_request.cc
+++ b/third_party/blink/renderer/modules/mediastream/user_media_request.cc
@@ -492,7 +492,7 @@
 
     // Feature policy deprecation messages.
     if (Audio()) {
-      if (!document->GetFrame()->IsFeatureEnabled(
+      if (!document->GetFrame()->DeprecatedIsFeatureEnabled(
               mojom::FeaturePolicyFeature::kMicrophone,
               ReportOptions::kReportOnFailure)) {
         UseCounter::Count(
@@ -500,7 +500,7 @@
       }
     }
     if (Video()) {
-      if (!document->GetFrame()->IsFeatureEnabled(
+      if (!document->GetFrame()->DeprecatedIsFeatureEnabled(
               mojom::FeaturePolicyFeature::kCamera,
               ReportOptions::kReportOnFailure)) {
         UseCounter::Count(document,
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni
index eccdc9d..928eb865 100644
--- a/third_party/blink/renderer/modules/modules_idl_files.gni
+++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -272,6 +272,8 @@
           "sensor/relative_orientation_sensor.idl",
           "sensor/sensor.idl",
           "sensor/sensor_error_event.idl",
+          "serial/serial.idl",
+          "serial/serial_port.idl",
           "service_worker/client.idl",
           "service_worker/clients.idl",
           "service_worker/extendable_event.idl",
@@ -635,6 +637,8 @@
           "sensor/sensor_error_event_init.idl",
           "sensor/sensor_options.idl",
           "sensor/spatial_sensor_options.idl",
+          "serial/serial_options.idl",
+          "serial/serial_port_request_options.idl",
           "service_worker/client_query_options.idl",
           "service_worker/extendable_event_init.idl",
           "service_worker/extendable_message_event_init.idl",
@@ -777,6 +781,8 @@
           "quota/worker_navigator_storage_quota.idl",
           "remoteplayback/html_media_element_remote_playback.idl",
           "screen_orientation/screen_screen_orientation.idl",
+          "serial/navigator_serial.idl",
+          "serial/worker_navigator_serial.idl",
           "service_worker/navigator_service_worker.idl",
           "speech/window_speech.idl",
           "speech/window_speech_synthesis.idl",
diff --git a/third_party/blink/renderer/modules/payments/payment_request.cc b/third_party/blink/renderer/modules/payments/payment_request.cc
index 295bb34..1fbfcaf 100644
--- a/third_party/blink/renderer/modules/payments/payment_request.cc
+++ b/third_party/blink/renderer/modules/payments/payment_request.cc
@@ -750,8 +750,8 @@
     return false;
 
   // 2. If Feature Policy is enabled, return the policy for "payment" feature.
-  return frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kPayment,
-                                 ReportOptions::kReportOnFailure);
+  return frame->DeprecatedIsFeatureEnabled(
+      mojom::FeaturePolicyFeature::kPayment, ReportOptions::kReportOnFailure);
 }
 
 void WarnIgnoringQueryQuotaForCanMakePayment(
diff --git a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
index 96bf1c6..ed942e0e 100644
--- a/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
+++ b/third_party/blink/renderer/modules/picture_in_picture/picture_in_picture_controller_impl.cc
@@ -54,7 +54,7 @@
   // If document is not allowed to use the policy-controlled feature named
   // "picture-in-picture", return kDisabledByFeaturePolicy status.
   if (RuntimeEnabledFeatures::PictureInPictureAPIEnabled() &&
-      !frame->IsFeatureEnabled(
+      !frame->DeprecatedIsFeatureEnabled(
           blink::mojom::FeaturePolicyFeature::kPictureInPicture)) {
     return Status::kDisabledByFeaturePolicy;
   }
diff --git a/third_party/blink/renderer/modules/sensor/sensor.cc b/third_party/blink/renderer/modules/sensor/sensor.cc
index e3f40710..2c96cf8 100644
--- a/third_party/blink/renderer/modules/sensor/sensor.cc
+++ b/third_party/blink/renderer/modules/sensor/sensor.cc
@@ -26,7 +26,7 @@
                         const Vector<mojom::FeaturePolicyFeature>& features) {
   return std::all_of(features.begin(), features.end(),
                      [frame](mojom::FeaturePolicyFeature feature) {
-                       return frame->IsFeatureEnabled(feature);
+                       return frame->DeprecatedIsFeatureEnabled(feature);
                      });
 }
 
diff --git a/third_party/blink/renderer/modules/serial/BUILD.gn b/third_party/blink/renderer/modules/serial/BUILD.gn
new file mode 100644
index 0000000..f135be8
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/BUILD.gn
@@ -0,0 +1,18 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/blink/renderer/modules/modules.gni")
+
+blink_modules_sources("serial") {
+  sources = [
+    "navigator_serial.cc",
+    "navigator_serial.h",
+    "serial.cc",
+    "serial.h",
+    "serial_port.cc",
+    "serial_port.h",
+    "worker_navigator_serial.cc",
+    "worker_navigator_serial.h",
+  ]
+}
diff --git a/third_party/blink/renderer/modules/serial/navigator_serial.cc b/third_party/blink/renderer/modules/serial/navigator_serial.cc
new file mode 100644
index 0000000..e9f8bd4
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/navigator_serial.cc
@@ -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.
+
+#include "third_party/blink/renderer/modules/serial/navigator_serial.h"
+
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/modules/serial/serial.h"
+
+namespace blink {
+
+const char NavigatorSerial::kSupplementName[] = "NavigatorSerial";
+
+NavigatorSerial& NavigatorSerial::From(Navigator& navigator) {
+  NavigatorSerial* supplement =
+      Supplement<Navigator>::From<NavigatorSerial>(navigator);
+  if (!supplement) {
+    supplement = new NavigatorSerial(navigator);
+    ProvideTo(navigator, supplement);
+  }
+  return *supplement;
+}
+
+Serial* NavigatorSerial::serial(Navigator& navigator) {
+  return NavigatorSerial::From(navigator).serial();
+}
+
+void NavigatorSerial::Trace(blink::Visitor* visitor) {
+  visitor->Trace(serial_);
+  Supplement<Navigator>::Trace(visitor);
+}
+
+NavigatorSerial::NavigatorSerial(Navigator& navigator)
+    : Supplement<Navigator>(navigator) {
+  if (navigator.GetFrame()) {
+    DCHECK(navigator.GetFrame()->GetDocument());
+    serial_ = Serial::Create(*navigator.GetFrame()->GetDocument());
+  }
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/serial/navigator_serial.h b/third_party/blink/renderer/modules/serial/navigator_serial.h
new file mode 100644
index 0000000..7267c35
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/navigator_serial.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 THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_
+
+#include "third_party/blink/renderer/core/frame/navigator.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class Serial;
+
+class NavigatorSerial final : public GarbageCollected<NavigatorSerial>,
+                              public Supplement<Navigator> {
+  USING_GARBAGE_COLLECTED_MIXIN(NavigatorSerial);
+
+ public:
+  static const char kSupplementName[];
+
+  static NavigatorSerial& From(Navigator&);
+
+  static Serial* serial(Navigator&);
+  Serial* serial() { return serial_; }
+
+  void Trace(Visitor*) override;
+
+ private:
+  explicit NavigatorSerial(Navigator&);
+
+  Member<Serial> serial_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_NAVIGATOR_SERIAL_H_
diff --git a/third_party/blink/renderer/modules/serial/navigator_serial.idl b/third_party/blink/renderer/modules/serial/navigator_serial.idl
new file mode 100644
index 0000000..380dbca
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/navigator_serial.idl
@@ -0,0 +1,13 @@
+// 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.
+
+// https://wicg.github.io/serial
+
+[
+    ImplementedAs=NavigatorSerial,
+    RuntimeEnabled=Serial,
+    SecureContext
+] partial interface Navigator {
+    [SameObject] readonly attribute Serial serial;
+};
diff --git a/third_party/blink/renderer/modules/serial/serial.cc b/third_party/blink/renderer/modules/serial/serial.cc
new file mode 100644
index 0000000..8c3a640
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/serial.cc
@@ -0,0 +1,43 @@
+// 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 "third_party/blink/renderer/modules/serial/serial.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+#include "third_party/blink/renderer/modules/event_target_modules_names.h"
+
+namespace blink {
+
+// static
+Serial* Serial::Create(ExecutionContext& execution_context) {
+  return new Serial(execution_context);
+}
+
+ExecutionContext* Serial::GetExecutionContext() const {
+  return ContextLifecycleObserver::GetExecutionContext();
+}
+
+const AtomicString& Serial::InterfaceName() const {
+  return EventTargetNames::Serial;
+}
+
+ScriptPromise Serial::getPorts(ScriptState* script_state) {
+  return ScriptPromise::RejectWithDOMException(
+      script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError));
+}
+
+ScriptPromise Serial::requestPort(ScriptState* script_state,
+                                  const SerialPortRequestOptions& options) {
+  return ScriptPromise::RejectWithDOMException(
+      script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError));
+}
+
+void Serial::Trace(Visitor* visitor) {
+  EventTargetWithInlineData::Trace(visitor);
+  ContextLifecycleObserver::Trace(visitor);
+}
+
+Serial::Serial(ExecutionContext& execution_context)
+    : ContextLifecycleObserver(&execution_context) {}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/serial/serial.h b/third_party/blink/renderer/modules/serial/serial.h
new file mode 100644
index 0000000..ead1ec0
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/serial.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 THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
+#include "third_party/blink/renderer/core/dom/events/event_target.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class ExecutionContext;
+class ScriptState;
+class SerialPortRequestOptions;
+
+class Serial final : public EventTargetWithInlineData,
+                     public ContextLifecycleObserver {
+  DEFINE_WRAPPERTYPEINFO();
+  USING_GARBAGE_COLLECTED_MIXIN(Serial);
+
+ public:
+  static Serial* Create(ExecutionContext& executionContext);
+
+  // EventTarget
+  ExecutionContext* GetExecutionContext() const override;
+  const AtomicString& InterfaceName() const override;
+
+  DEFINE_ATTRIBUTE_EVENT_LISTENER(connect);
+  DEFINE_ATTRIBUTE_EVENT_LISTENER(disconnect);
+  ScriptPromise getPorts(ScriptState*);
+  ScriptPromise requestPort(ScriptState*, const SerialPortRequestOptions&);
+
+  void Trace(Visitor*) override;
+
+ private:
+  explicit Serial(ExecutionContext&);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_H_
diff --git a/third_party/blink/renderer/modules/serial/serial.idl b/third_party/blink/renderer/modules/serial/serial.idl
new file mode 100644
index 0000000..b883b8e0
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/serial.idl
@@ -0,0 +1,19 @@
+// 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.
+
+// https://wicg.github.io/serial
+
+[
+    Exposed(Window Serial,DedicatedWorker Serial),
+    SecureContext
+] interface Serial : EventTarget {
+    attribute EventHandler onconnect;
+    attribute EventHandler ondisconnect;
+
+    [CallWith=ScriptState, MeasureAs=SerialGetPorts]
+    Promise<sequence<SerialPort>> getPorts();
+
+    [CallWith=ScriptState, MeasureAs=SerialRequestPort, Exposed=Window]
+    Promise<SerialPort> requestPort(SerialPortRequestOptions options);
+};
diff --git a/third_party/blink/renderer/modules/serial/serial_options.idl b/third_party/blink/renderer/modules/serial/serial_options.idl
new file mode 100644
index 0000000..ccb1446
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/serial_options.idl
@@ -0,0 +1,20 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/serial
+
+enum ParityType {
+  "none",
+  "even",
+  "odd",
+};
+
+dictionary SerialOptions {
+  long baudrate = 9600;
+  octet databits = 8;
+  octet stopbits = 1;
+  ParityType parity = "none";
+  long buffersize = 255;
+  boolean rtscts = false;
+};
diff --git a/third_party/blink/renderer/modules/serial/serial_port.cc b/third_party/blink/renderer/modules/serial/serial_port.cc
new file mode 100644
index 0000000..10739a4d
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/serial_port.cc
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/serial/serial_port.h"
+#include "third_party/blink/renderer/core/dom/dom_exception.h"
+
+namespace blink {
+
+ScriptValue SerialPort::in(ScriptState* script_state) {
+  return ScriptValue::CreateNull(script_state);
+}
+
+ScriptValue SerialPort::out(ScriptState* script_state) {
+  return ScriptValue::CreateNull(script_state);
+}
+
+ScriptPromise SerialPort::open(ScriptState* script_state,
+                               const SerialOptions& options) {
+  return ScriptPromise::RejectWithDOMException(
+      script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError));
+}
+
+ScriptPromise SerialPort::close(ScriptState* script_state) {
+  return ScriptPromise::RejectWithDOMException(
+      script_state, DOMException::Create(DOMExceptionCode::kNotSupportedError));
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/serial/serial_port.h b/third_party/blink/renderer/modules/serial/serial_port.h
new file mode 100644
index 0000000..baadd7b06
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/serial_port.h
@@ -0,0 +1,30 @@
+// 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 THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_
+
+#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+
+namespace blink {
+
+class ScriptState;
+class SerialOptions;
+
+class SerialPort final : public ScriptWrappable {
+  DEFINE_WRAPPERTYPEINFO();
+
+ public:
+  ScriptValue in(ScriptState*);
+  ScriptValue out(ScriptState*);
+
+  ScriptPromise open(ScriptState*, const SerialOptions& options);
+  ScriptPromise close(ScriptState*);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_SERIAL_PORT_H_
diff --git a/third_party/blink/renderer/modules/serial/serial_port.idl b/third_party/blink/renderer/modules/serial/serial_port.idl
new file mode 100644
index 0000000..794b9875
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/serial_port.idl
@@ -0,0 +1,22 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://wicg.github.io/serial
+
+[
+    Exposed(Window Serial,DedicatedWorker Serial),
+    SecureContext
+] interface SerialPort {
+    // TODO(https://crbug.com/888165): "any" is used here because the IDL
+    // processor does not recognize ReadableStream or WritableStream when
+    // implemented with V8 extras.
+    [CallWith=ScriptState] readonly attribute any in;
+    [CallWith=ScriptState] readonly attribute any out;
+
+    [CallWith=ScriptState, MeasureAs=SerialPortOpen]
+    Promise<void> open(SerialOptions options);
+
+    [CallWith=ScriptState, MeasureAs=SerialPortClose]
+    Promise<void> close();
+};
diff --git a/third_party/blink/renderer/modules/serial/serial_port_request_options.idl b/third_party/blink/renderer/modules/serial/serial_port_request_options.idl
new file mode 100644
index 0000000..8e9c05c
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/serial_port_request_options.idl
@@ -0,0 +1,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.
+
+// https://wicg.github.io/serial
+
+dictionary SerialPortRequestOptions {
+};
diff --git a/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc b/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
new file mode 100644
index 0000000..a5a6b08
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/worker_navigator_serial.cc
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/modules/serial/worker_navigator_serial.h"
+
+#include "third_party/blink/renderer/modules/serial/serial.h"
+
+namespace blink {
+
+const char WorkerNavigatorSerial::kSupplementName[] = "WorkerNavigatorSerial";
+
+WorkerNavigatorSerial& WorkerNavigatorSerial::From(WorkerNavigator& navigator) {
+  WorkerNavigatorSerial* supplement =
+      Supplement<WorkerNavigator>::From<WorkerNavigatorSerial>(navigator);
+  if (!supplement) {
+    supplement = new WorkerNavigatorSerial(navigator);
+    ProvideTo(navigator, supplement);
+  }
+  return *supplement;
+}
+
+Serial* WorkerNavigatorSerial::serial(ScriptState* script_state,
+                                      WorkerNavigator& navigator) {
+  return WorkerNavigatorSerial::From(navigator).serial(script_state);
+}
+
+Serial* WorkerNavigatorSerial::serial(ScriptState* script_state) {
+  if (!serial_) {
+    auto* execution_context = ExecutionContext::From(script_state);
+    DCHECK(execution_context);
+
+    // TODO(https://crbug.com/839117): Remove this check once the Exposed
+    // attribute is fixed to only expose this property in dedicated workers.
+    if (execution_context->IsDedicatedWorkerGlobalScope())
+      serial_ = Serial::Create(*execution_context);
+  }
+  return serial_;
+}
+
+void WorkerNavigatorSerial::Trace(blink::Visitor* visitor) {
+  visitor->Trace(serial_);
+  Supplement<WorkerNavigator>::Trace(visitor);
+}
+
+WorkerNavigatorSerial::WorkerNavigatorSerial(WorkerNavigator& navigator)
+    : Supplement<WorkerNavigator>(navigator) {}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/modules/serial/worker_navigator_serial.h b/third_party/blink/renderer/modules/serial/worker_navigator_serial.h
new file mode 100644
index 0000000..8ff078d
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/worker_navigator_serial.h
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_
+
+#include "third_party/blink/renderer/core/workers/worker_navigator.h"
+#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
+
+namespace blink {
+
+class ScriptState;
+class Serial;
+
+class WorkerNavigatorSerial final
+    : public GarbageCollected<WorkerNavigatorSerial>,
+      public Supplement<WorkerNavigator> {
+  USING_GARBAGE_COLLECTED_MIXIN(WorkerNavigatorSerial);
+
+ public:
+  static const char kSupplementName[];
+
+  static WorkerNavigatorSerial& From(WorkerNavigator&);
+
+  static Serial* serial(ScriptState*, WorkerNavigator&);
+  Serial* serial(ScriptState*);
+
+  void Trace(Visitor*) override;
+
+ private:
+  explicit WorkerNavigatorSerial(WorkerNavigator&);
+
+  Member<Serial> serial_;
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_SERIAL_WORKER_NAVIGATOR_SERIAL_H_
diff --git a/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl b/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl
new file mode 100644
index 0000000..c95d2b0
--- /dev/null
+++ b/third_party/blink/renderer/modules/serial/worker_navigator_serial.idl
@@ -0,0 +1,14 @@
+// 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.
+
+// https://wicg.github.io/serial
+
+[
+    Exposed=DedicatedWorker,
+    ImplementedAs=WorkerNavigatorSerial,
+    RuntimeEnabled=Serial,
+    SecureContext
+] partial interface WorkerNavigator {
+    [CallWith=ScriptState, SameObject] readonly attribute Serial serial;
+};
diff --git a/third_party/blink/renderer/modules/vr/navigator_vr.cc b/third_party/blink/renderer/modules/vr/navigator_vr.cc
index 8eec6dee..01dae7eb 100644
--- a/third_party/blink/renderer/modules/vr/navigator_vr.cc
+++ b/third_party/blink/renderer/modules/vr/navigator_vr.cc
@@ -144,8 +144,8 @@
         script_state, DOMException::Create(DOMExceptionCode::kInvalidStateError,
                                            kNotAssociatedWithDocumentMessage));
   }
-  if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr,
-                               ReportOptions::kReportOnFailure)) {
+  if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr,
+                                         ReportOptions::kReportOnFailure)) {
     return ScriptPromise::RejectWithDOMException(
         script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
                                            kFeaturePolicyBlockedMessage));
diff --git a/third_party/blink/renderer/modules/webaudio/base_audio_context.h b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
index a29a9b6..48bae6f 100644
--- a/third_party/blink/renderer/modules/webaudio/base_audio_context.h
+++ b/third_party/blink/renderer/modules/webaudio/base_audio_context.h
@@ -353,6 +353,16 @@
 
   const String& Uuid() const { return uuid_; }
 
+  // The audio thread relies on the main thread to perform some operations
+  // over the objects that it owns and controls; |ScheduleMainThreadCleanup()|
+  // posts the task to initiate those.
+  void ScheduleMainThreadCleanup();
+
+  // Handles promise resolving, stopping and finishing up of audio source nodes
+  // etc. Actions that should happen, but can happen asynchronously to the
+  // audio thread making rendering progress.
+  void PerformCleanupOnMainThread();
+
  private:
   friend class AudioContextAutoplayTest;
 
@@ -392,18 +402,6 @@
   // these Promises.
   void ResolvePromisesForUnpause();
 
-  // The audio thread relies on the main thread to perform some operations
-  // over the objects that it owns and controls; |ScheduleMainThreadCleanup()|
-  // posts the task to initiate those.
-  //
-  // That is, we combine all those sub-tasks into one task action for
-  // convenience and performance, |PerformCleanupOnMainThread()|. It handles
-  // promise resolving, stopping and finishing up of audio source nodes etc.
-  // Actions that should happen, but can happen asynchronously to the
-  // audio thread making rendering progress.
-  void ScheduleMainThreadCleanup();
-  void PerformCleanupOnMainThread();
-
   // When the context is going away, reject any pending script promise
   // resolvers.
   virtual void RejectPendingResolvers();
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
index fa3c1d6..576b7a4 100644
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_context.cc
@@ -379,6 +379,8 @@
   }
 
   is_rendering_started_ = false;
+
+  PerformCleanupOnMainThread();
 }
 
 bool OfflineAudioContext::HandlePreOfflineRenderTasks() {
diff --git a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
index 4d08522c..21ff4de 100644
--- a/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
+++ b/third_party/blink/renderer/modules/webmidi/navigator_web_midi.cc
@@ -102,7 +102,7 @@
   UseCounter::CountCrossOriginIframe(
       document, WebFeature::kRequestMIDIAccessIframe_ObscuredByFootprinting);
 
-  if (!document.GetFrame()->IsFeatureEnabled(
+  if (!document.GetFrame()->DeprecatedIsFeatureEnabled(
           mojom::FeaturePolicyFeature::kMidiFeature,
           ReportOptions::kReportOnFailure)) {
     UseCounter::Count(document, WebFeature::kMidiDisabledByFeaturePolicy);
diff --git a/third_party/blink/renderer/modules/webusb/usb.cc b/third_party/blink/renderer/modules/webusb/usb.cc
index c15089f..b911b99 100644
--- a/third_party/blink/renderer/modules/webusb/usb.cc
+++ b/third_party/blink/renderer/modules/webusb/usb.cc
@@ -115,7 +115,8 @@
     if (execution_context && execution_context->IsDocument()) {
       ToDocument(execution_context)
           ->GetFrame()
-          ->ReportFeaturePolicyViolation(mojom::FeaturePolicyFeature::kUsb);
+          ->DeprecatedReportFeaturePolicyViolation(
+              mojom::FeaturePolicyFeature::kUsb);
     }
     return ScriptPromise::RejectWithDOMException(
         script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
@@ -139,8 +140,8 @@
         DOMException::Create(DOMExceptionCode::kNotSupportedError));
   }
 
-  if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kUsb,
-                               ReportOptions::kReportOnFailure)) {
+  if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kUsb,
+                                         ReportOptions::kReportOnFailure)) {
     return ScriptPromise::RejectWithDOMException(
         script_state, DOMException::Create(DOMExceptionCode::kSecurityError,
                                            kFeaturePolicyBlocked));
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc
index 287e88c0..8cb4dbb 100644
--- a/third_party/blink/renderer/modules/xr/xr.cc
+++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -73,8 +73,8 @@
     did_log_requestDevice_ = true;
   }
 
-  if (!frame->IsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr,
-                               ReportOptions::kReportOnFailure)) {
+  if (!frame->DeprecatedIsFeatureEnabled(mojom::FeaturePolicyFeature::kWebVr,
+                                         ReportOptions::kReportOnFailure)) {
     // Only allow the call to be made if the appropraite feature policy is in
     // place.
     return ScriptPromise::RejectWithDOMException(
diff --git a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
index 6ec3f41..e7c2c29 100644
--- a/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
+++ b/third_party/blink/renderer/platform/bindings/v8_per_isolate_data.cc
@@ -162,6 +162,13 @@
   data->active_script_wrappables_.Clear();
 
   // Detach V8's garbage collector.
+  if (RuntimeEnabledFeatures::HeapUnifiedGarbageCollectionEnabled()) {
+    // Need to finalize an already running garbage collection as otherwise
+    // callbacks are missing and state gets out of sync.
+    ThreadState::Current()->FinishIncrementalMarkingIfRunning(
+        BlinkGC::kHeapPointersOnStack, BlinkGC::kAtomicMarking,
+        BlinkGC::kEagerSweeping, BlinkGC::GCReason::kThreadTerminationGC);
+  }
   isolate->SetEmbedderHeapTracer(nullptr);
   if (data->script_wrappable_visitor_->WrapperTracingInProgress())
     data->script_wrappable_visitor_->AbortTracing();
diff --git a/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc b/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc
index c48be7b..8616bf8 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_color_params_test.cc
@@ -7,7 +7,6 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/renderer/platform/graphics/color_correction_test_utils.h"
 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
-#include "third_party/skia/include/core/SkColorSpaceXform.h"
 #include "ui/gfx/color_space.h"
 
 namespace blink {
@@ -17,56 +16,20 @@
 // to the canvas, the target gfx::ColorSpace is returned by CanvasColorParams::
 // GetStorageGfxColorSpace(). This test verifies that the two different color
 // spaces are approximately the same for different CanvasColorParam objects.
-// This test does not use SkColorSpace::Equals() since it is sensitive to
-// rounding issues (floats don't round-trip perfectly through ICC fixed point).
-// Instead, it color converts a pixel and compares the result. Furthermore, this
-// test does not include sRGB as target color space since we use
-// SkColorSpaceXformCanvas for sRGB targets and GetSkColorSpaceForSkSurfaces()
-// returns nullptr for the surface.
 TEST(CanvasColorParamsTest, MatchSkColorSpaceWithGfxColorSpace) {
-  sk_sp<SkColorSpace> src_rgb_color_space = SkColorSpace::MakeSRGB();
-  std::unique_ptr<uint8_t[]> src_pixel(new uint8_t[4]{32, 96, 160, 255});
-
   CanvasColorSpace canvas_color_spaces[] = {
       kSRGBCanvasColorSpace, kRec2020CanvasColorSpace, kP3CanvasColorSpace,
   };
-
   for (int iter_color_space = 0; iter_color_space < 3; iter_color_space++) {
     CanvasColorParams color_params(canvas_color_spaces[iter_color_space],
                                    kF16CanvasPixelFormat, kNonOpaque);
-
-    std::unique_ptr<SkColorSpaceXform> color_space_xform_canvas =
-        SkColorSpaceXform::New(src_rgb_color_space.get(),
-                               color_params.GetSkColorSpace().get());
-    std::unique_ptr<SkColorSpaceXform> color_space_xform_media =
-        SkColorSpaceXform::New(
-            src_rgb_color_space.get(),
-            color_params.GetStorageGfxColorSpace().ToSkColorSpace().get());
-
-    std::unique_ptr<uint8_t[]> transformed_pixel_canvas(
-        new uint8_t[color_params.BytesPerPixel()]());
-    std::unique_ptr<uint8_t[]> transformed_pixel_media(
-        new uint8_t[color_params.BytesPerPixel()]());
-
-    SkColorSpaceXform::ColorFormat transformed_color_format =
-        color_params.BytesPerPixel() == 4
-            ? SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat
-            : SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
-
-    EXPECT_TRUE(color_space_xform_canvas->apply(
-        transformed_color_format, transformed_pixel_canvas.get(),
-        SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat, src_pixel.get(),
-        1, SkAlphaType::kPremul_SkAlphaType));
-
-    EXPECT_TRUE(color_space_xform_media->apply(
-        transformed_color_format, transformed_pixel_media.get(),
-        SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat, src_pixel.get(),
-        1, SkAlphaType::kPremul_SkAlphaType));
-
-    ColorCorrectionTestUtils::CompareColorCorrectedPixels(
-        transformed_pixel_canvas.get(), transformed_pixel_media.get(), 1,
-        kPixelFormat_hhhh, kAlphaMultiplied, kUnpremulRoundTripTolerance);
-    }
+    sk_sp<SkColorSpace> canvas_drawing_color_space =
+        color_params.GetSkColorSpace();
+    sk_sp<SkColorSpace> canvas_media_color_space =
+        color_params.GetStorageGfxColorSpace().ToSkColorSpace();
+    ASSERT_TRUE(ColorCorrectionTestUtils::MatchColorSpace(
+        canvas_drawing_color_space, canvas_media_color_space));
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc b/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
index a7b1c89..25fdcaa 100644
--- a/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
+++ b/third_party/blink/renderer/platform/graphics/color_correction_test_utils.cc
@@ -6,6 +6,7 @@
 
 #include "base/sys_byteorder.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/third_party/skcms/skcms.h"
 
 namespace blink {
 
@@ -66,6 +67,33 @@
   return SkColorSpace::Make(colorspin_profile);
 }
 
+sk_sp<SkColorSpace>
+ColorCorrectionTestUtils::ColorSpaceConversionToSkColorSpace(
+    ColorSpaceConversion conversion) {
+  if (conversion == kColorSpaceConversion_Default ||
+      conversion == kColorSpaceConversion_SRGB) {
+    return SkColorSpace::MakeSRGB();
+  }
+  if (conversion == kColorSpaceConversion_LinearRGB)
+    return SkColorSpace::MakeSRGBLinear();
+  if (conversion == kColorSpaceConversion_P3) {
+    return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
+                                 SkColorSpace::kDCIP3_D65_Gamut);
+  }
+  if (conversion == kColorSpaceConversion_Rec2020) {
+    return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma,
+                                 SkColorSpace::kRec2020_Gamut);
+  }
+  return nullptr;
+}
+
+String ColorCorrectionTestUtils::ColorSpaceConversionToString(
+    ColorSpaceConversion color_space_conversion) {
+  static const Vector<String> kConversions = {
+      "none", "default", "preserve", "srgb", "linear-rgb", "p3", "rec2020"};
+  return kConversions[static_cast<uint8_t>(color_space_conversion)];
+}
+
 void ColorCorrectionTestUtils::CompareColorCorrectedPixels(
     const void* actual_pixels,
     const void* expected_pixels,
@@ -227,32 +255,23 @@
 }
 
 bool ColorCorrectionTestUtils::MatchColorSpace(
-    SkColorSpace* src_color_space,
-    SkColorSpace* dst_color_space,
-    float xyz_d50_component_tolerance) {
+    sk_sp<SkColorSpace> src_color_space,
+    sk_sp<SkColorSpace> dst_color_space) {
   if ((!src_color_space && dst_color_space) ||
       (src_color_space && !dst_color_space))
     return false;
-  if (src_color_space) {
-    const SkMatrix44* src_matrix = src_color_space->toXYZD50();
-    const SkMatrix44* dst_matrix = dst_color_space->toXYZD50();
-    for (int i = 0; i < 4; i++) {
-      for (int j = 0; j < 4; j++) {
-        if (fabs(src_matrix->get(i, j) - dst_matrix->get(i, j)) >
-            xyz_d50_component_tolerance) {
-          return false;
-        }
-      }
-    }
-  }
-  return true;
+  if (!src_color_space && !dst_color_space)
+    return true;
+  skcms_ICCProfile src_profile, dst_profile;
+  src_color_space->toProfile(&src_profile);
+  dst_color_space->toProfile(&dst_profile);
+  return skcms_ApproximatelyEqualProfiles(&src_profile, &dst_profile);
 }
 
 bool ColorCorrectionTestUtils::MatchSkImages(sk_sp<SkImage> src_image,
                                              sk_sp<SkImage> dst_image,
                                              unsigned uint8_tolerance,
                                              float f16_tolerance,
-                                             float xyz_d50_component_tolerance,
                                              bool compare_alpha) {
   if ((!src_image && dst_image) || (src_image && !dst_image))
     return false;
@@ -265,8 +284,10 @@
 
   if (compare_alpha && src_image->alphaType() != dst_image->alphaType())
     return false;
-  if (!MatchColorSpace(src_image->colorSpace(), dst_image->colorSpace(),
-                       xyz_d50_component_tolerance)) {
+  // Color type is not checked since the decoded image does not have a specific
+  // color type, unless it is drawn onto a surface or readPixels() is called.
+  if (!MatchColorSpace(src_image->refColorSpace(),
+                       dst_image->refColorSpace())) {
     return false;
   }
 
diff --git a/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h b/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h
index 486f07f..1f79335 100644
--- a/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h
+++ b/third_party/blink/renderer/platform/graphics/color_correction_test_utils.h
@@ -9,8 +9,8 @@
 
 #include "third_party/blink/renderer/platform/graphics/graphics_types.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 #include "third_party/skia/include/core/SkImage.h"
-#include "third_party/skia/third_party/skcms/skcms.h"
 
 namespace blink {
 
@@ -31,9 +31,25 @@
   kUnpremulRoundTripTolerance,
 };
 
+enum ColorSpaceConversion {
+  kColorSpaceConversion_None,
+  kColorSpaceConversion_Default,
+  kColorSpaceConversion_Preserve,
+  kColorSpaceConversion_SRGB,
+  kColorSpaceConversion_LinearRGB,
+  kColorSpaceConversion_P3,
+  kColorSpaceConversion_Rec2020,
+  kColorSpaceConversion_Last = kColorSpaceConversion_Rec2020,
+};
+
 class ColorCorrectionTestUtils {
  public:
+  // ImageBitmap color space conversion test utils
   static sk_sp<SkColorSpace> ColorSpinSkColorSpace();
+  static sk_sp<SkColorSpace> ColorSpaceConversionToSkColorSpace(
+      ColorSpaceConversion conversion);
+  static String ColorSpaceConversionToString(
+      ColorSpaceConversion color_space_conversion);
 
   static void CompareColorCorrectedPixels(
       const void* actual_pixels,
@@ -53,15 +69,13 @@
       std::unique_ptr<uint8_t[]>& converted_pixels,
       PixelFormat pixel_format_for_f16_canvas);
 
-  static bool MatchColorSpace(SkColorSpace* src_color_space,
-                              SkColorSpace* dst_color_space,
-                              float xyz_d50_component_tolerance);
+  static bool MatchColorSpace(sk_sp<SkColorSpace> src_color_space,
+                              sk_sp<SkColorSpace> dst_color_space);
 
   static bool MatchSkImages(sk_sp<SkImage> src_image,
                             sk_sp<SkImage> dst_image,
                             unsigned uint8_tolerance,
                             float f16_tolerance,
-                            float xyz_d50_component_tolerance,
                             bool compare_alpha);
 
  private:
diff --git a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
index b04c567..45a3ce6 100644
--- a/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
+++ b/third_party/blink/renderer/platform/graphics/gpu/drawing_buffer.cc
@@ -57,7 +57,7 @@
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/functional.h"
 #include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h"
-#include "third_party/skia/include/core/SkColorSpaceXform.h"
+#include "third_party/skia/include/core/SkPixmap.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/gpu/GrContext.h"
 #include "third_party/skia/include/gpu/gl/GrGLTypes.h"
@@ -1367,15 +1367,15 @@
   }
 
   if (op == WebGLImageConversion::kAlphaDoPremultiply) {
-    std::unique_ptr<SkColorSpaceXform> xform =
-        SkColorSpaceXform::New(SkColorSpace::MakeSRGBLinear().get(),
-                               SkColorSpace::MakeSRGBLinear().get());
-    SkColorSpaceXform::ColorFormat color_format =
-        SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
+    auto color_type = kRGBA_8888_SkColorType;
     if (data_type != GL_UNSIGNED_BYTE)
-      color_format = SkColorSpaceXform::ColorFormat::kRGBA_F16_ColorFormat;
-    xform->apply(color_format, pixels, color_format, pixels, width * height,
-                 kPremul_SkAlphaType);
+      color_type = kRGBA_F16_SkColorType;
+    const auto src =
+        SkImageInfo::Make(width, height, color_type, kUnpremul_SkAlphaType);
+    const auto dst =
+        SkImageInfo::Make(width, height, color_type, kPremul_SkAlphaType);
+    SkPixmap{src, pixels, src.minRowBytes()}.readPixels(
+        SkPixmap{dst, pixels, dst.minRowBytes()});
   } else if (op != WebGLImageConversion::kAlphaDoNothing) {
     NOTREACHED();
   }
diff --git a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
index 2e601824..a9bf22f 100644
--- a/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
@@ -63,8 +63,8 @@
   constexpr int kMaxMismatches = 10;
   for (int y = 0; y < bounds.Height(); ++y) {
     for (int x = 0; x < bounds.Width(); ++x) {
-      SkPMColor pixel1 = *bitmap1.getAddr32(x, y);
-      SkPMColor pixel2 = *bitmap2.getAddr32(x, y);
+      SkColor pixel1 = bitmap1.getColor(x, y);
+      SkColor pixel2 = bitmap2.getColor(x, y);
       if (pixel1 != pixel2) {
         if (!RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled())
           return false;
diff --git a/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc b/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc
index 895dc591..4f3e4ac3 100644
--- a/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
-#include "third_party/skia/include/core/SkColorPriv.h"
 
 namespace blink {
 
@@ -160,11 +159,11 @@
   return abs(c1 - c2) > 2;
 }
 
-static bool PMColorsDiffer(SkPMColor p1, SkPMColor p2) {
-  return PixelComponentsDiffer(SkGetPackedA32(p1), SkGetPackedA32(p2)) ||
-         PixelComponentsDiffer(SkGetPackedR32(p1), SkGetPackedR32(p2)) ||
-         PixelComponentsDiffer(SkGetPackedG32(p1), SkGetPackedG32(p2)) ||
-         PixelComponentsDiffer(SkGetPackedB32(p1), SkGetPackedB32(p2));
+static bool PixelsDiffer(SkColor p1, SkColor p2) {
+  return PixelComponentsDiffer(SkColorGetA(p1), SkColorGetA(p2)) ||
+         PixelComponentsDiffer(SkColorGetR(p1), SkColorGetR(p2)) ||
+         PixelComponentsDiffer(SkColorGetG(p1), SkColorGetG(p2)) ||
+         PixelComponentsDiffer(SkColorGetB(p1), SkColorGetB(p2));
 }
 
 void RasterInvalidationTracking::CheckUnderInvalidations(
@@ -216,9 +215,9 @@
     int layer_y = bitmap_y + rect.Y();
     for (int bitmap_x = 0; bitmap_x < rect.Width(); ++bitmap_x) {
       int layer_x = bitmap_x + rect.X();
-      SkPMColor old_pixel = *old_bitmap.getAddr32(bitmap_x, bitmap_y);
-      SkPMColor new_pixel = *new_bitmap.getAddr32(bitmap_x, bitmap_y);
-      if (PMColorsDiffer(old_pixel, new_pixel) &&
+      SkColor old_pixel = old_bitmap.getColor(bitmap_x, bitmap_y);
+      SkColor new_pixel = new_bitmap.getColor(bitmap_x, bitmap_y);
+      if (PixelsDiffer(old_pixel, new_pixel) &&
           !invalidation_region.Contains(IntPoint(layer_x, layer_y))) {
         if (mismatching_pixels < kMaxMismatchesToReport) {
           RasterUnderInvalidation under_invalidation = {layer_x, layer_y,
diff --git a/third_party/blink/renderer/platform/image-decoders/image_frame_test.cc b/third_party/blink/renderer/platform/image-decoders/image_frame_test.cc
index 908a772..2b63ae6e 100644
--- a/third_party/blink/renderer/platform/image-decoders/image_frame_test.cc
+++ b/third_party/blink/renderer/platform/image-decoders/image_frame_test.cc
@@ -5,7 +5,7 @@
 #include "third_party/blink/renderer/platform/image-decoders/image_frame.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkColorSpaceXform.h"
+#include "third_party/skia/third_party/skcms/skcms.h"
 
 namespace blink {
 namespace {
@@ -26,20 +26,16 @@
     src_8888 = SkPackARGB32(src_8888_a, src_8888_r, src_8888_g, src_8888_b);
     dst_8888 = SkPackARGB32(0xA0, 0x60, 0x70, 0x80);
 
-    typedef SkColorSpaceXform::ColorFormat ColorFormat;
-    color_format_8888 = ColorFormat::kBGRA_8888_ColorFormat;
+    pixel_format_n32 = skcms_PixelFormat_RGBA_8888;
     if (kN32_SkColorType == kRGBA_8888_SkColorType)
-      color_format_8888 = ColorFormat::kRGBA_8888_ColorFormat;
-    color_format_f16 = ColorFormat::kRGBA_F16_ColorFormat;
-    color_format_f32 = ColorFormat::kRGBA_F32_ColorFormat;
+      pixel_format_n32 = skcms_PixelFormat_BGRA_8888;
 
-    sk_sp<SkColorSpace> srgb_linear = SkColorSpace::MakeSRGBLinear();
-    SkColorSpaceXform::Apply(srgb_linear.get(), color_format_f16, &src_f16,
-                             srgb_linear.get(), color_format_8888, &src_8888, 1,
-                             SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp);
-    SkColorSpaceXform::Apply(srgb_linear.get(), color_format_f16, &dst_f16,
-                             srgb_linear.get(), color_format_8888, &dst_8888, 1,
-                             SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp);
+    skcms_Transform(&src_8888, pixel_format_n32, skcms_AlphaFormat_Unpremul,
+                    nullptr, &src_f16, skcms_PixelFormat_RGBA_hhhh,
+                    skcms_AlphaFormat_Unpremul, nullptr, 1);
+    skcms_Transform(&dst_8888, pixel_format_n32, skcms_AlphaFormat_Unpremul,
+                    nullptr, &dst_f16, skcms_PixelFormat_RGBA_hhhh,
+                    skcms_AlphaFormat_Unpremul, nullptr, 1);
   }
 
  protected:
@@ -47,21 +43,19 @@
   unsigned src_8888_a, src_8888_r, src_8888_g, src_8888_b;
   ImageFrame::PixelData src_8888, dst_8888;
   ImageFrame::PixelDataF16 src_f16, dst_f16;
-  SkColorSpaceXform::ColorFormat color_format_8888, color_format_f16,
-      color_format_f32;
+  skcms_PixelFormat pixel_format_n32;
 
   void ConvertN32ToF32(float* dst, ImageFrame::PixelData src) {
-    sk_sp<SkColorSpace> srgb_linear = SkColorSpace::MakeSRGBLinear();
-    SkColorSpaceXform::Apply(srgb_linear.get(), color_format_f32, dst,
-                             srgb_linear.get(), color_format_8888, &src, 1,
-                             SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp);
+    skcms_Transform(&src, pixel_format_n32, skcms_AlphaFormat_Unpremul, nullptr,
+                    dst, skcms_PixelFormat_RGBA_ffff,
+                    skcms_AlphaFormat_Unpremul, nullptr, 1);
   }
 
   void ConvertF16ToF32(float* dst, ImageFrame::PixelDataF16 src) {
-    sk_sp<SkColorSpace> srgb_linear = SkColorSpace::MakeSRGBLinear();
-    SkColorSpaceXform::Apply(srgb_linear.get(), color_format_f32, dst,
-                             srgb_linear.get(), color_format_f16, &src, 1,
-                             SkColorSpaceXform::AlphaOp::kPreserve_AlphaOp);
+    skcms_Transform(&src, skcms_PixelFormat_RGBA_hhhh,
+                    skcms_AlphaFormat_Unpremul, nullptr, dst,
+                    skcms_PixelFormat_RGBA_ffff, skcms_AlphaFormat_Unpremul,
+                    nullptr, 1);
   }
 };
 
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 9bd5f954..5313537 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -637,12 +637,15 @@
     },
     {
       name: "LayoutNG",
-      implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFlexBox", "EditingNG"],
+      implied_by: ["LayoutNGBlockFragmentation", "LayoutNGFieldset", "LayoutNGFlexBox", "EditingNG"],
     },
     {
       name: "LayoutNGBlockFragmentation",
     },
     {
+      name: "LayoutNGFieldset",
+    },
+    {
       name: "LayoutNGFlexBox",
     },
     {
@@ -1133,6 +1136,10 @@
       status: "experimental",
     },
     {
+      name: "Serial",
+      status: "experimental",
+    },
+    {
       name: "ServiceWorkerScriptFullCodeCache",
     },
     {
diff --git a/tools/binary_size/diagnose_bloat.py b/tools/binary_size/diagnose_bloat.py
index 6092a3c..3ec9b63 100755
--- a/tools/binary_size/diagnose_bloat.py
+++ b/tools/binary_size/diagnose_bloat.py
@@ -847,32 +847,6 @@
   atexit.register(_GenRestoreFunc(subrepo))
 
 
-# Used by binary size trybot.
-def _DiffMain(args):
-  parser = argparse.ArgumentParser()
-  parser.add_argument('--before-dir', required=True)
-  parser.add_argument('--after-dir', required=True)
-  parser.add_argument('--apk-name', required=True)
-  parser.add_argument('--diff-type', required=True, choices=['native', 'sizes'])
-  parser.add_argument('--diff-output', required=True)
-  args = parser.parse_args(args)
-
-  is_native_diff = args.diff_type == 'native'
-  if is_native_diff:
-    supersize_path = os.path.join(_BINARY_SIZE_DIR, 'supersize')
-    diff = NativeDiff(args.apk_name + '.size', supersize_path)
-  else:
-    diff = ResourceSizesDiff(args.apk_name)
-
-  diff.ProduceDiff(args.before_dir, args.after_dir)
-  lines = diff.DetailedResults() if is_native_diff else diff.Summary()
-
-  with open(args.diff_output, 'w') as f:
-    f.writelines(l + '\n' for l in lines)
-    stat = diff.summary_stat
-    f.write('\n{}={}\n'.format(*stat[:2]))
-
-
 def main():
   parser = argparse.ArgumentParser(
       description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
@@ -965,8 +939,6 @@
   if len(sys.argv) == 1:
     parser.print_help()
     return 1
-  if sys.argv[1] == 'diff':
-    return _DiffMain(sys.argv[2:])
 
   args = parser.parse_args()
   log_level = logging.DEBUG if args.verbose else logging.INFO
diff --git a/tools/binary_size/libsupersize/canned_queries.py b/tools/binary_size/libsupersize/canned_queries.py
index 1d9a5770..4aeeeb5b 100644
--- a/tools/binary_size/libsupersize/canned_queries.py
+++ b/tools/binary_size/libsupersize/canned_queries.py
@@ -5,6 +5,7 @@
 """Contains a set of Chrome-specific size queries."""
 
 import logging
+
 import models
 
 
diff --git a/tools/binary_size/libsupersize/console.py b/tools/binary_size/libsupersize/console.py
index 0517acf9..455314b 100644
--- a/tools/binary_size/libsupersize/console.py
+++ b/tools/binary_size/libsupersize/console.py
@@ -153,17 +153,7 @@
     """
     before = before if before is not None else self._size_infos[0]
     after = after if after is not None else self._size_infos[1]
-    ret = diff.Diff(before, after)
-    if sort:
-      syms = ret.symbols  # Triggers clustering.
-      logging.debug('Grouping')
-      # Group path aliases so that functions defined in headers will be sorted
-      # by their actual size rather than shown as many small symbols.
-      syms = syms.GroupedByAliases(same_name_only=True)
-      logging.debug('Sorting')
-      ret.symbols = syms.Sorted()
-    logging.debug('Diff complete')
-    return ret
+    return diff.Diff(before, after, sort=sort)
 
   def _PrintFunc(self, obj=None, verbose=False, summarize=True, recursive=False,
                  use_pager=None, to_file=None):
diff --git a/tools/binary_size/libsupersize/diff.py b/tools/binary_size/libsupersize/diff.py
index 0915f99..2a0b9601 100644
--- a/tools/binary_size/libsupersize/diff.py
+++ b/tools/binary_size/libsupersize/diff.py
@@ -121,7 +121,7 @@
   return models.DeltaSymbolGroup(all_deltas)
 
 
-def Diff(before, after):
+def Diff(before, after, sort=False):
   """Diffs two SizeInfo objects. Returns a DeltaSizeInfo."""
   assert isinstance(before, models.SizeInfo)
   assert isinstance(after, models.SizeInfo)
@@ -132,4 +132,15 @@
       section_sizes[k] = v
 
   symbol_diff = _DiffSymbolGroups(before.raw_symbols, after.raw_symbols)
-  return models.DeltaSizeInfo(before, after, section_sizes, symbol_diff)
+  ret = models.DeltaSizeInfo(before, after, section_sizes, symbol_diff)
+
+  if sort:
+    syms = ret.symbols  # Triggers clustering.
+    logging.debug('Grouping')
+    # Group path aliases so that functions defined in headers will be sorted
+    # by their actual size rather than shown as many small symbols.
+    syms = syms.GroupedByAliases(same_name_only=True)
+    logging.debug('Sorting')
+    ret.symbols = syms.Sorted()
+  logging.debug('Diff complete')
+  return ret
diff --git a/tools/binary_size/libsupersize/html_report.py b/tools/binary_size/libsupersize/html_report.py
index fa8873b..f2d8a4a0 100644
--- a/tools/binary_size/libsupersize/html_report.py
+++ b/tools/binary_size/libsupersize/html_report.py
@@ -191,38 +191,28 @@
   return meta, file_nodes.values()
 
 
-def BuildReport(out_file, size_file, before_size_file=(None, None),
-                all_symbols=False):
+def BuildReportFromSizeInfo(out_path, size_info, all_symbols=False):
   """Builds a .ndjson report for a .size file.
 
   Args:
-    out_file: File object to save JSON report to.
-    size_file: Size file to use as input. Tuple of path and file object.
-    before_size_file: If used, creates a diff report where |size_file| is the
-      newer .size file. Tuple of path and file object.
+    out_path: Path to save JSON report to.
+    size_info: A SizeInfo or DeltaSizeInfo to use for the report.
     all_symbols: If true, all symbols will be included in the report rather
       than truncated.
   """
   logging.info('Reading .size file')
-  diff_mode = any(before_size_file)
-
-  size_info = archive.LoadAndPostProcessSizeInfo(*size_file)
-  if diff_mode:
-    before_size_info = archive.LoadAndPostProcessSizeInfo(*before_size_file)
-    after_size_info = size_info
-
-    size_info = diff.Diff(before_size_info, after_size_info)
-    symbols = size_info.raw_symbols
+  symbols = size_info.raw_symbols
+  is_diff = symbols.IsDelta()
+  if is_diff:
     symbols = symbols.WhereDiffStatusIs(models.DIFF_STATUS_UNCHANGED).Inverted()
-  else:
-    symbols = size_info.raw_symbols
 
   meta, tree_nodes = _MakeTreeViewList(symbols, all_symbols)
+  logging.info('Created %d tree nodes', len(tree_nodes))
   meta.update({
-    'diff_mode': diff_mode,
+    'diff_mode': is_diff,
     'section_sizes': size_info.section_sizes,
   })
-  if diff_mode:
+  if is_diff:
     meta.update({
       'before_metadata': size_info.before.metadata,
       'after_metadata': size_info.after.metadata,
@@ -239,13 +229,14 @@
     'check_circular': False,
   }
 
-  json.dump(meta, out_file, **json_dump_args)
-  out_file.write('\n')
-
-  for tree_node in tree_nodes:
-    json.dump(tree_node, out_file, **json_dump_args)
+  with codecs.open(out_path, 'w', encoding='ascii') as out_file:
+    json.dump(meta, out_file, **json_dump_args)
     out_file.write('\n')
 
+    for tree_node in tree_nodes:
+      json.dump(tree_node, out_file, **json_dump_args)
+      out_file.write('\n')
+
 
 def _MakeDirIfDoesNotExist(rel_path):
   """Ensures a directory exists."""
@@ -278,13 +269,13 @@
   if not args.output_report_file.endswith('.ndjson'):
     parser.error('Output must end with ".ndjson"')
 
-  with codecs.open(args.output_report_file, 'w', encoding='ascii') as out_file:
-    BuildReport(
-      out_file,
-      size_file=(args.input_size_file, None),
-      before_size_file=(args.diff_with, None),
-      all_symbols=args.all_symbols
-    )
+  size_info = archive.LoadAndPostProcessSizeInfo(args.input_size_file)
+  if args.diff_with:
+    before_size_info = archive.LoadAndPostProcessSizeInfo(args.diff_with)
+    size_info = diff.Diff(before_size_info, size_info)
+
+  BuildReportFromSizeInfo(
+      args.output_report_file, size_info, all_symbols=args.all_symbols)
 
   msg = [
       'Done!',
diff --git a/tools/binary_size/trybot_commit_size_checker.py b/tools/binary_size/trybot_commit_size_checker.py
index 664be05..d93b46ae 100755
--- a/tools/binary_size/trybot_commit_size_checker.py
+++ b/tools/binary_size/trybot_commit_size_checker.py
@@ -3,46 +3,192 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Fails if a try job increases binary size unexpectedly."""
+"""Creates several files used by the size trybot to monitor size regressions."""
 
 import argparse
+import collections
+import json
+import logging
+import os
 import sys
 
+sys.path.append(os.path.join(os.path.dirname(__file__), 'libsupersize'))
+import archive
+import diagnose_bloat
+import diff
+import describe
+import html_report
+import models
 
-_MAX_UNNOTICED_INCREASE = 16 * 1024
+_MAX_DEX_METHOD_COUNT_INCREASE = 50
+_MAX_NORMALIZED_INCREASE = 16 * 1024
+_MAX_PAK_INCREASE = 1024
+
+_NORMALIZED_APK_SIZE_DETAILS = (
+    'See https://chromium.googlesource.com/chromium/src/+/master/docs/speed/'
+    'binary_size/metrics.md#Normalized-APK-Size '
+    'for an explanation of Normalized APK Size')
+
+
+class _SizeDelta(collections.namedtuple(
+    'SizeDelta', ['name', 'units', 'expected', 'actual', 'details'])):
+
+  @property
+  def explanation(self):
+    return '{}: expected max: {} {}, got {} {}\n{}'.format(
+        self.name, self.expected, self.units, self.actual, self.units,
+        self.details)
+
+  def _IsAllowable(self):
+    return self.actual <= self.expected
+
+  def __cmp__(self, other):
+    return cmp(self.name, other.name)
+
+
+def _CreateAndWriteMethodCountDelta(symbols, output_path):
+  dex_symbols = symbols.WhereInSection(models.SECTION_DEX_METHOD)
+  dex_added = dex_symbols.WhereDiffStatusIs(models.DIFF_STATUS_ADDED)
+  dex_removed = dex_symbols.WhereDiffStatusIs(models.DIFF_STATUS_REMOVED)
+  dex_added_count, dex_removed_count = len(dex_added), len(dex_removed)
+  dex_net_added = dex_added_count - dex_removed_count
+
+  dex_expl = 'Added: {}\n{}\n\nRemoved: {}\n{}'.format(
+      dex_added_count,
+      '\n'.join(s.name for s in dex_added.SortedByName()),
+      dex_removed_count,
+      '\n'.join(s.name for s in dex_removed.SortedByName()))
+
+  with open(output_path, 'w') as f:
+    f.writelines(dex_expl)
+
+  return _SizeDelta('Dex Methods', 'methods', _MAX_DEX_METHOD_COUNT_INCREASE,
+                    dex_net_added, dex_expl)
+
+
+def _CreateAndWriteResourceSizesDelta(apk_name, before_dir, after_dir,
+                                     output_path):
+  sizes_diff = diagnose_bloat.ResourceSizesDiff(apk_name)
+  sizes_diff.ProduceDiff(before_dir, after_dir)
+
+  with open(output_path, 'w') as f:
+    f.writelines(l + '\n' for l in sizes_diff.Summary())
+
+  return _SizeDelta('Normalized APK Size', 'bytes', _MAX_NORMALIZED_INCREASE,
+                    sizes_diff.summary_stat.value, _NORMALIZED_APK_SIZE_DETAILS)
+
+
+def _CreateAndWriteSupersizeDiff(apk_name, before_dir, after_dir, output_path):
+  before_size_path = os.path.join(before_dir, apk_name + '.size')
+  after_size_path = os.path.join(after_dir, apk_name + '.size')
+  before = archive.LoadAndPostProcessSizeInfo(before_size_path)
+  after = archive.LoadAndPostProcessSizeInfo(after_size_path)
+  size_info_delta = diff.Diff(before, after, sort=True)
+
+  with open(output_path, 'w') as f:
+    f.writelines(l + '\n' for l in describe.GenerateLines(size_info_delta))
+
+  return size_info_delta
+
+
+def _CreateUncompressedPakSizeDeltas(symbols):
+  pak_symbols = symbols.Filter(lambda s:
+      s.size > 0 and
+      bool(s.flags & models.FLAG_UNCOMPRESSED) and
+      s.section_name == models.SECTION_PAK_NONTRANSLATED)
+  return [_SizeDelta('Uncompressed Pak Entry', 'bytes', _MAX_PAK_INCREASE,
+                     pak.after_symbol.size, pak.full_name)
+          for pak in pak_symbols]
 
 
 def main():
   parser = argparse.ArgumentParser()
-  parser.add_argument('--author', help='CL author')
-  parser.add_argument('--resource-sizes-diff',
-                      help='Path to resource sizes diff produced by '
-                           '"diagnose_bloat.py diff sizes".')
+  parser.add_argument('--author', required=True, help='CL author')
+  parser.add_argument('--apk-name', required=True,
+                      help='Name of the apk (ex. Name.apk)')
+  parser.add_argument('--before-dir', required=True,
+                      help='Directory containing the APK from reference build.')
+  parser.add_argument('--after-dir', required=True,
+                      help='Directory containing APK for the new build.')
+  parser.add_argument('--resource-sizes-diff-path', required=True,
+                      help='Output path for the resource_sizes.py diff.')
+  parser.add_argument('--supersize-diff-path', required=True,
+                      help='Output path for the Supersize diff.')
+  parser.add_argument('--dex-method-count-diff-path', required=True,
+                      help='Output path for the dex method count diff.')
+  parser.add_argument('--ndjson-path', required=True,
+                      help='Output path for the Supersize HTML report.')
+  parser.add_argument('--results-path', required=True,
+                      help='Output path for the trybot result .json file.')
+  parser.add_argument('-v', '--verbose', action='store_true')
   args = parser.parse_args()
 
-  # Last line looks like:
-  # MonochromePublic.apk_Specifics normalized apk size=1234
-  with open(args.resource_sizes_diff) as f:
-    last_line = f.readlines()[-1]
-    size_delta = int(last_line.partition('=')[2])
+  if args.verbose:
+    logging.basicConfig(level=logging.INFO)
+
+  logging.info('Creating Supersize diff')
+  delta_size_info = _CreateAndWriteSupersizeDiff(
+      args.apk_name, args.before_dir, args.after_dir, args.supersize_diff_path)
+  changed_symbols = delta_size_info.raw_symbols.WhereDiffStatusIs(
+      models.DIFF_STATUS_UNCHANGED).Inverted()
+
+  # Monitor dex method growth since this correlates closely with APK size and
+  # may affect our dex file structure.
+  logging.info('Checking dex symbols')
+  size_deltas = set()
+  size_deltas.add(
+      _CreateAndWriteMethodCountDelta(
+          changed_symbols, args.dex_method_count_diff_path))
+
+  # Check for uncompressed .pak file entries being added to avoid unnecessary
+  # bloat.
+  logging.info('Checking pak symbols')
+  size_deltas.update(_CreateUncompressedPakSizeDeltas(changed_symbols))
+
+  # Normalized APK Size is the main metric we use to monitor binary size.
+  logging.info('Creating sizes diff')
+  size_deltas.add(
+      _CreateAndWriteResourceSizesDelta(
+          args.apk_name, args.before_dir, args.after_dir,
+          args.resource_sizes_diff_path))
+
+  # .ndjson can be consumed by the html viewer.
+  logging.info('Creating HTML Report')
+  html_report.BuildReportFromSizeInfo(
+      args.ndjson_path, delta_size_info, all_symbols=True)
 
   is_roller = '-autoroll' in args.author
 
   # Useful for bot debugging to have these printed out:
-  print 'Is Roller:', is_roller
-  print 'Increase:', size_delta
+  for delta in sorted(size_deltas):
+    print '{}\n\n'.format(delta.explanation)
 
-  if size_delta > _MAX_UNNOTICED_INCREASE and not is_roller:
-    # Failure message printed to stderr, so flush first.
-    sys.stdout.flush()
-    failure_message = """
+  passing_deltas = set(m for m in size_deltas if m._IsAllowable())
+  failing_deltas = size_deltas - passing_deltas
 
-Binary size increase is non-trivial (where "non-trivial" means the normalized \
-size increased by more than {} bytes).
+  result = 'passed' if is_roller or len(failing_deltas) == 0 else 'failed'
+  message = """
 
-Please look at the symbol diffs from the "Show Resource Sizes Diff" and the \
-"Show Supersize Diff" bot steps. Try and understand the growth and see if it \
-can be mitigated. There is guidance at:
+Binary size checks {}.
+
+*******************************************************************************
+FAILING:
+
+{}
+
+*******************************************************************************
+
+PASSING:
+
+{}
+
+*******************************************************************************
+
+Please look at the symbol diffs from the "Show Resource Sizes Diff",
+"Show Supersize Diff", and "Dex Method Count", and "Supersize HTML Report" bot
+steps. Try and understand the growth and see if it can be mitigated.
+
+There is guidance at:
 
 https://chromium.googlesource.com/chromium/src/+/master/docs/speed/apk_size_regressions.md#Debugging-Apk-Size-Increase
 
@@ -59,11 +205,14 @@
 Binary-Size: Increase needed to reduce runtime of a common user flow.
 Binary-Size: Increase needed to implement a feature, and I've already spent a
     non-trivial amount of time trying to reduce its size.
-""".format(_MAX_UNNOTICED_INCREASE)
-    # Make blank lines not blank prevent them from being stripped.
-    # https://crbug.com/855671
-    failure_message.replace('\n\n', '\n.\n')
-    sys.exit(failure_message)
+""".format(result,
+           '\n\n'.join(d.explanation for d in sorted(failing_deltas)),
+           '\n\n'.join(d.explanation for d in sorted(passing_deltas)))
+  # Make blank lines not blank prevent them from being stripped.
+  # https://crbug.com/855671
+  message.replace('\n\n', '\n.\n')
+  with open(args.results_path, 'w') as f:
+    json.dump({'status_code': len(failing_deltas), 'details': message}, f)
 
 
 if __name__ == '__main__':
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 424cafec..00f565b 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -20222,6 +20222,10 @@
   <int value="2542" label="PaymentAddressLanguageCode"/>
   <int value="2543" label="DocumentDomainBlockedCrossOriginAccess"/>
   <int value="2544" label="DocumentDomainEnabledCrossOriginAccess"/>
+  <int value="2545" label="SerialGetPorts"/>
+  <int value="2546" label="SerialRequestPort"/>
+  <int value="2547" label="SerialPortOpen"/>
+  <int value="2548" label="SerialPortClose"/>
 </enum>
 
 <enum name="FeaturePolicyFeature">
@@ -43739,14 +43743,13 @@
 </enum>
 
 <enum name="SBDownloadFeedbackUploadResult">
-  <int value="0" label="SUCCESS"/>
-  <int value="1" label="UPLOAD_SUCCESS"/>
-  <int value="2" label="UPLOAD_CANCELLED"/>
-  <int value="3" label="UPLOAD_METADATA_NET_ERROR"/>
-  <int value="4" label="UPLOAD_METADATA_RESPONSE_ERROR"/>
-  <int value="5" label="UPLOAD_FILE_NET_ERROR"/>
-  <int value="6" label="UPLOAD_FILE_RESPONSE_ERROR"/>
-  <int value="7" label="UPLOAD_COMPLETE_RESPONSE_ERROR"/>
+  <int value="0" label="UPLOAD_SUCCESS"/>
+  <int value="1" label="UPLOAD_CANCELLED"/>
+  <int value="2" label="UPLOAD_METADATA_NET_ERROR"/>
+  <int value="3" label="UPLOAD_METADATA_RESPONSE_ERROR"/>
+  <int value="4" label="UPLOAD_FILE_NET_ERROR"/>
+  <int value="5" label="UPLOAD_FILE_RESPONSE_ERROR"/>
+  <int value="6" label="UPLOAD_COMPLETE_RESPONSE_ERROR"/>
 </enum>
 
 <enum name="SBFileTypeUpdateResult">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f5501002..a9cb875 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -72530,6 +72530,17 @@
   </summary>
 </histogram>
 
+<histogram name="PasswordManager.InvalidtHttpsCredentialsNeedToBeCleared"
+    enum="BooleanNeedsClearing" expires_after="M73">
+  <owner>vabr@chromium.org</owner>
+  <owner>jdoerrie@chromium.org</owner>
+  <summary>
+    Records once on startup whether forms with wrong signon_realm created by
+    HTTP to HTTPS migration need to be removed. See https://crbug.com/881731 for
+    more details.
+  </summary>
+</histogram>
+
 <histogram name="PasswordManager.IsSyncPasswordHashSaved"
     enum="IsSyncPasswordHashSaved">
   <owner>dvadym@chromium.org</owner>
@@ -83438,11 +83449,14 @@
 
 <histogram name="Renderer4.GestureScrollingThreadStatus"
     enum="ScrollingThreadStatus">
+  <obsolete>
+    Deprecated 9/2018 and merged into Renderer4.MainThreadGestureScrollReason.
+  </obsolete>
   <owner>tdresser@chromium.org</owner>
   <summary>
-    For every gesture, we record whether the scroll occurred on the main thread,
-    on the compositor thread, or on the compositor thread but blocked on the
-    main thread. The last case will happen when there is a blocking event
+    For every touch scroll, we record whether the scroll occurred on the main
+    thread, on the compositor thread, or on the compositor thread but blocked on
+    the main thread. The last case will happen when there is a blocking event
     listener.
   </summary>
 </histogram>
@@ -83696,7 +83710,8 @@
     Ideally we'd always scroll on the impl thread, but there are a variety of
     situations where we need to scroll on main. We should try to drive these
     down. For every gesture, we record whether or not the scroll occurred on the
-    main thread, and if it did, what the reason was.
+    main thread or it should scroll on the impl thread but is blocked on main
+    thread, and if it did, what the reason was.
   </summary>
 </histogram>
 
@@ -83707,7 +83722,8 @@
     Ideally we'd always scroll on the impl thread, but there are a variety of
     situations where we need to scroll on main. We should try to drive these
     down. For every wheel tick, we record whether or not the the scroll occurred
-    on the main thread, and if it did, what the reason was.
+    on the main thread or it should scroll on the impl thread but is blocked on
+    main thread, and if it did, what the reason was.
   </summary>
 </histogram>
 
@@ -83978,6 +83994,9 @@
 
 <histogram name="Renderer4.WheelScrollingThreadStatus"
     enum="ScrollingThreadStatus">
+  <obsolete>
+    Deprecated 9/2018 and merged into Renderer4.MainThreadWheelScrollReason.
+  </obsolete>
   <owner>tdresser@chromium.org</owner>
   <summary>
     For every wheel tick, we record whether the scroll occurred on the main
@@ -86737,6 +86756,26 @@
   </summary>
 </histogram>
 
+<histogram name="SafeBrowsing.ContentsSize.Height" units="DIPs"
+    expires_after="M73">
+  <owner>jialiul@chrormium.org</owner>
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    Records the height of content area when the user opens a new browser window
+    or when the user finishes resizing a browser window.
+  </summary>
+</histogram>
+
+<histogram name="SafeBrowsing.ContentsSize.Width" units="DIPs"
+    expires_after="M73">
+  <owner>jialiul@chrormium.org</owner>
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    Records the width of content area when the user opens a new browser window
+    or when the user finishes resizing a browser window.
+  </summary>
+</histogram>
+
 <histogram name="SafeBrowsing.EnabledSettingChanged" enum="BooleanEnabled">
   <obsolete>
     Not in the code anymore (10/2015).
diff --git a/ui/accessibility/ax_node_data.cc b/ui/accessibility/ax_node_data.cc
index 9db9aed2..76810a1a 100644
--- a/ui/accessibility/ax_node_data.cc
+++ b/ui/accessibility/ax_node_data.cc
@@ -565,6 +565,11 @@
   actions = ModifyFlag(actions, static_cast<uint32_t>(action_enum), true);
 }
 
+void AXNodeData::RemoveState(ax::mojom::State state_enum) {
+  DCHECK_NE(state_enum, ax::mojom::State::kNone);
+  state = ModifyFlag(state, static_cast<uint32_t>(state_enum), false);
+}
+
 std::string AXNodeData::ToString() const {
   std::string result;
 
diff --git a/ui/accessibility/ax_node_data.h b/ui/accessibility/ax_node_data.h
index 468b13f..c7d3320e 100644
--- a/ui/accessibility/ax_node_data.h
+++ b/ui/accessibility/ax_node_data.h
@@ -134,6 +134,9 @@
   void AddState(ax::mojom::State state_enum);
   void AddAction(ax::mojom::Action action_enum);
 
+  // Remove bits in the given enum's corresponding bitfield.
+  void RemoveState(ax::mojom::State state_enum);
+
   // Helper functions to get some common int attributes with some specific
   // enum types:
   ax::mojom::CheckedState GetCheckedState() const {
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 9f340f7..f48f30e 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -1178,7 +1178,8 @@
     if (target) {
       (*targets)[index] = static_cast<IAccessible*>(target);
       (*targets)[index]->AddRef();
-      index++;
+      if (++index > count)
+        break;
     }
   }
   *n_targets = index;
diff --git a/ui/accessibility/platform/ax_system_caret_win.cc b/ui/accessibility/platform/ax_system_caret_win.cc
index bd475d5..dd91704c 100644
--- a/ui/accessibility/platform/ax_system_caret_win.cc
+++ b/ui/accessibility/platform/ax_system_caret_win.cc
@@ -24,6 +24,7 @@
   data_.role = ax::mojom::Role::kCaret;
   // |get_accState| should return 0 which means that the caret is visible.
   data_.state = 0;
+  data_.AddState(ax::mojom::State::kInvisible);
   // According to MSDN, "Edit" should be the name of the caret object.
   data_.SetName(L"Edit");
   data_.offset_container_id = -1;
@@ -54,13 +55,43 @@
 void AXSystemCaretWin::MoveCaretTo(const gfx::Rect& bounds) {
   if (bounds.IsEmpty())
     return;
-  data_.location = gfx::RectF(bounds);
-  if (event_target_) {
+
+  // If the caret has non-empty bounds, assume it has been made visible.
+  bool newly_visible = false;
+  if (data_.HasState(ax::mojom::State::kInvisible)) {
+    newly_visible = true;
+    data_.RemoveState(ax::mojom::State::kInvisible);
+  }
+
+  if (!event_target_)
+    return;
+
+  if (newly_visible) {
+    ::NotifyWinEvent(EVENT_OBJECT_SHOW, event_target_, OBJID_CARET,
+                     -caret_->GetUniqueId());
+  }
+
+  gfx::RectF new_location(bounds);
+  // Avoid redundant caret move events (if the location stays the same), but
+  // always fire when it's made visible again.
+  if (data_.location != new_location || newly_visible) {
+    data_.location = new_location;
     ::NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, event_target_, OBJID_CARET,
                      -caret_->GetUniqueId());
   }
 }
 
+void AXSystemCaretWin::Hide() {
+  if (!data_.HasState(ax::mojom::State::kInvisible)) {
+    data_.AddState(ax::mojom::State::kInvisible);
+    data_.location.set_width(0);
+    if (event_target_) {
+      ::NotifyWinEvent(EVENT_OBJECT_HIDE, event_target_, OBJID_CARET,
+                       -caret_->GetUniqueId());
+    }
+  }
+}
+
 const AXNodeData& AXSystemCaretWin::GetData() const {
   return data_;
 }
diff --git a/ui/accessibility/platform/ax_system_caret_win.h b/ui/accessibility/platform/ax_system_caret_win.h
index 03f4bf9..a4d2392 100644
--- a/ui/accessibility/platform/ax_system_caret_win.h
+++ b/ui/accessibility/platform/ax_system_caret_win.h
@@ -31,6 +31,7 @@
 
   Microsoft::WRL::ComPtr<IAccessible> GetCaret() const;
   void MoveCaretTo(const gfx::Rect& bounds);
+  void Hide();
 
  private:
   // |AXPlatformNodeDelegate| members.
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index 420df48..d37158e 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -466,6 +466,17 @@
   DCHECK(
       !cc::MainThreadScrollingReason::HasNonCompositedScrollReasons(reasons));
 
+  int32_t event_disposition_result =
+      (device == blink::kWebGestureDeviceTouchpad ? mouse_wheel_result_
+                                                  : touch_result_);
+  if (event_disposition_result == DID_NOT_HANDLE) {
+    // We should also collect main thread scrolling reasons if a scroll event
+    // scrolls on impl thread but is blocked by main thread event handlers.
+    reasons |= (device == blink::kWebGestureDeviceTouchpad
+                    ? cc::MainThreadScrollingReason::kWheelEventHandlerRegion
+                    : cc::MainThreadScrollingReason::kTouchEventHandlerRegion);
+  }
+
   // UMA_HISTOGRAM_ENUMERATION requires that the enum_max must be strictly
   // greater than the sample value. kMainThreadScrollingReasonCount doesn't
   // include the NotScrollingOnMain enum but the histograms do so adding
@@ -511,51 +522,6 @@
   }
 }
 
-void InputHandlerProxy::RecordScrollingThreadStatus(
-    blink::WebGestureDevice device,
-    uint32_t reasons) {
-  if (device != blink::kWebGestureDeviceTouchpad &&
-      device != blink::kWebGestureDeviceTouchscreen) {
-    return;
-  }
-
-  ScrollingThreadStatus scrolling_thread_status = SCROLLING_ON_MAIN;
-  if (reasons == cc::MainThreadScrollingReason::kNotScrollingOnMain) {
-    int32_t event_disposition_result =
-        (device == blink::kWebGestureDeviceTouchpad ? mouse_wheel_result_
-                                                    : touch_result_);
-    switch (event_disposition_result) {
-      case kEventDispositionUndefined:
-      case DID_NOT_HANDLE_NON_BLOCKING_DUE_TO_FLING:
-      case DID_HANDLE_NON_BLOCKING:
-      case DROP_EVENT:
-        scrolling_thread_status = SCROLLING_ON_COMPOSITOR;
-        break;
-      case DID_NOT_HANDLE:
-        scrolling_thread_status = SCROLLING_ON_COMPOSITOR_BLOCKED_ON_MAIN;
-        break;
-      default:
-        NOTREACHED();
-        scrolling_thread_status = SCROLLING_ON_COMPOSITOR;
-    }
-  }
-
-  // UMA_HISTOGRAM_ENUMERATION requires that the enum_max must be strictly
-  // greater than the sample value.
-  const uint32_t kScrolingThreadStatusEnumMax =
-      ScrollingThreadStatus::LAST_SCROLLING_THREAD_STATUS_VALUE + 1;
-
-  if (device == blink::kWebGestureDeviceTouchscreen) {
-    UMA_HISTOGRAM_ENUMERATION("Renderer4.GestureScrollingThreadStatus",
-                              scrolling_thread_status,
-                              kScrolingThreadStatusEnumMax);
-  } else {
-    UMA_HISTOGRAM_ENUMERATION("Renderer4.WheelScrollingThreadStatus",
-                              scrolling_thread_status,
-                              kScrolingThreadStatusEnumMax);
-  }
-}
-
 bool InputHandlerProxy::ShouldAnimate(bool has_precise_scroll_deltas) const {
 #if defined(OS_MACOSX)
   // Mac does not smooth scroll wheel events (crbug.com/574283).
@@ -646,9 +612,6 @@
   RecordMainThreadScrollingReasons(gesture_event.SourceDevice(),
                                    scroll_status.main_thread_scrolling_reasons);
 
-  RecordScrollingThreadStatus(gesture_event.SourceDevice(),
-                              scroll_status.main_thread_scrolling_reasons);
-
   InputHandlerProxy::EventDisposition result = DID_NOT_HANDLE;
   scroll_sequence_ignored_ = false;
   in_inertial_scrolling_ = false;
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 9f5bd515..c0d6d6f 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -1375,234 +1375,6 @@
   testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler);
 }
 
-TEST_P(InputHandlerProxyTest, MainThreadScrollingMouseWheelHistograms) {
-  input_handler_->RecordMainThreadScrollingReasonsForTest(
-      blink::kWebGestureDeviceTouchpad,
-      cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects |
-          cc::MainThreadScrollingReason::kThreadedScrollingDisabled |
-          cc::MainThreadScrollingReason::kPageOverlay |
-          cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
-
-  EXPECT_THAT(
-      histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
-      testing::ElementsAre(base::Bucket(1, 1), base::Bucket(3, 1),
-                           base::Bucket(5, 1)));
-
-  // We only want to record "Handling scroll from main thread" reason if it's
-  // the only reason. If it's not the only reason, the "real" reason for
-  // scrolling on main is something else, and we only want to pay attention to
-  // that reason. So we should only include this reason in the histogram when
-  // its on its own.
-  input_handler_->RecordMainThreadScrollingReasonsForTest(
-      blink::kWebGestureDeviceTouchpad,
-      cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
-
-  EXPECT_THAT(
-      histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
-      testing::ElementsAre(base::Bucket(1, 1), base::Bucket(3, 1),
-                           base::Bucket(5, 1), base::Bucket(14, 1)));
-}
-
-TEST_P(InputHandlerProxyTest, GestureScrollingThreadStatusHistogram) {
-  VERIFY_AND_RESET_MOCKS();
-
-  WebTouchEvent touch_start(WebInputEvent::kTouchStart,
-                            WebInputEvent::kNoModifiers,
-                            WebInputEvent::GetStaticTimeStampForTests());
-  touch_start.touches_length = 1;
-  touch_start.touch_start_or_first_touch_move = true;
-  touch_start.touches[0] =
-      CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10);
-
-  WebGestureEvent gesture_scroll_begin(
-      WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers,
-      WebInputEvent::GetStaticTimeStampForTests(),
-      blink::kWebGestureDeviceTouchscreen);
-
-  WebGestureEvent gesture_scroll_end(
-      WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers,
-      WebInputEvent::GetStaticTimeStampForTests(),
-      blink::kWebGestureDeviceTouchscreen);
-
-  // Touch start with passive event listener.
-  EXPECT_CALL(
-      mock_input_handler_,
-      EventListenerTypeForTouchStartOrMoveAt(
-          testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_))
-      .WillOnce(testing::Return(
-          cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
-  EXPECT_CALL(
-      mock_input_handler_,
-      GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove))
-      .WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
-  EXPECT_CALL(mock_client_,
-              SetWhiteListedTouchAction(testing::_, testing::_, testing::_))
-      .WillOnce(testing::Return());
-
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(touch_start));
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_begin));
-
-  EXPECT_THAT(histogram_tester().GetAllSamples(
-                  "Renderer4.GestureScrollingThreadStatus"),
-              testing::ElementsAre(base::Bucket(0, 1)));
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_end));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Touch event with HANDLER_ON_SCROLLING_LAYER event listener.
-  EXPECT_CALL(
-      mock_input_handler_,
-      EventListenerTypeForTouchStartOrMoveAt(
-          testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_))
-      .WillOnce(
-          testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType::
-                              HANDLER_ON_SCROLLING_LAYER));
-  EXPECT_CALL(mock_client_,
-              SetWhiteListedTouchAction(testing::_, testing::_, testing::_))
-      .WillOnce(testing::Return());
-
-  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(touch_start));
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_begin));
-
-  EXPECT_THAT(histogram_tester().GetAllSamples(
-                  "Renderer4.GestureScrollingThreadStatus"),
-              testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1)));
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_end));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Gesture scrolling on main thread.
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kMainThreadScrollState));
-  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_begin));
-
-  EXPECT_THAT(histogram_tester().GetAllSamples(
-                  "Renderer4.GestureScrollingThreadStatus"),
-              testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1),
-                                   base::Bucket(2, 1)));
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
-  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_end));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
-TEST_P(InputHandlerProxyTest, WheelScrollingThreadStatusHistogram) {
-  VERIFY_AND_RESET_MOCKS();
-
-  WebMouseWheelEvent wheel(WebInputEvent::kMouseWheel,
-                           WebInputEvent::kControlKey,
-                           WebInputEvent::GetStaticTimeStampForTests());
-
-  WebGestureEvent gesture_scroll_begin(
-      WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers,
-      WebInputEvent::GetStaticTimeStampForTests(),
-      blink::kWebGestureDeviceTouchpad);
-
-  WebGestureEvent gesture_scroll_end(
-      WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers,
-      WebInputEvent::GetStaticTimeStampForTests(),
-      blink::kWebGestureDeviceTouchpad);
-
-  // Wheel event with passive event listener.
-  EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_))
-      .WillRepeatedly(testing::Return(false));
-  EXPECT_CALL(mock_input_handler_,
-              GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
-      .WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel));
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_begin));
-
-  EXPECT_THAT(
-      histogram_tester().GetAllSamples("Renderer4.WheelScrollingThreadStatus"),
-      testing::ElementsAre(base::Bucket(0, 1)));
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_end));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Wheel event with blocking event listener. If there is a wheel event handler
-  // at the point, we do not need to call GetEventListenerProperties since it
-  // indicates kBlocking.
-  EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_))
-      .WillRepeatedly(testing::Return(true));
-  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
-  EXPECT_EQ(expected_disposition_, input_handler_->HandleInputEvent(wheel));
-
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kImplThreadScrollState));
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_begin));
-
-  EXPECT_THAT(
-      histogram_tester().GetAllSamples("Renderer4.WheelScrollingThreadStatus"),
-      testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1)));
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
-  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_end));
-
-  VERIFY_AND_RESET_MOCKS();
-
-  // Wheel scrolling on main thread.
-  EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_))
-      .WillRepeatedly(testing::Return(true));
-  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
-      .WillOnce(testing::Return(kMainThreadScrollState));
-  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_begin));
-
-  EXPECT_THAT(
-      histogram_tester().GetAllSamples("Renderer4.WheelScrollingThreadStatus"),
-      testing::ElementsAre(base::Bucket(0, 1), base::Bucket(1, 1),
-                           base::Bucket(2, 1)));
-
-  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
-  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
-  EXPECT_EQ(expected_disposition_,
-            input_handler_->HandleInputEvent(gesture_scroll_end));
-
-  VERIFY_AND_RESET_MOCKS();
-}
-
 TEST_F(InputHandlerProxyEventQueueTest, VSyncAlignedGestureScroll) {
   base::HistogramTester histogram_tester;
 
@@ -2103,8 +1875,423 @@
   testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
 }
 
+class InputHandlerProxyMainThreadScrollingReasonTest
+    : public InputHandlerProxyTest {
+ public:
+  enum TestEventType {
+    Touch,
+    MouseWheel,
+  };
+
+  InputHandlerProxyMainThreadScrollingReasonTest() : InputHandlerProxyTest() {}
+  ~InputHandlerProxyMainThreadScrollingReasonTest() { input_handler_.reset(); }
+
+  void SetupEvents(TestEventType type) {
+    touch_start_ =
+        WebTouchEvent(WebInputEvent::kTouchStart, WebInputEvent::kNoModifiers,
+                      WebInputEvent::GetStaticTimeStampForTests());
+    touch_end_ =
+        WebTouchEvent(WebInputEvent::kTouchEnd, WebInputEvent::kNoModifiers,
+                      WebInputEvent::GetStaticTimeStampForTests());
+    wheel_event_ = WebMouseWheelEvent(
+        WebInputEvent::kMouseWheel, WebInputEvent::kControlKey,
+        WebInputEvent::GetStaticTimeStampForTests());
+    gesture_scroll_begin_ = WebGestureEvent(
+        WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers,
+        WebInputEvent::GetStaticTimeStampForTests(),
+        type == TestEventType::MouseWheel
+            ? blink::kWebGestureDeviceTouchpad
+            : blink::kWebGestureDeviceTouchscreen);
+    gesture_scroll_end_ = WebGestureEvent(
+        WebInputEvent::kGestureScrollEnd, WebInputEvent::kNoModifiers,
+        WebInputEvent::GetStaticTimeStampForTests(),
+        type == TestEventType::MouseWheel
+            ? blink::kWebGestureDeviceTouchpad
+            : blink::kWebGestureDeviceTouchscreen);
+    touch_start_.touches_length = 1;
+    touch_start_.touch_start_or_first_touch_move = true;
+    touch_start_.touches[0] =
+        CreateWebTouchPoint(WebTouchPoint::kStatePressed, 10, 10);
+
+    touch_end_.touches_length = 1;
+  }
+
+  base::HistogramBase::Sample GetBucketSample(uint32_t reason) {
+    if (reason == cc::MainThreadScrollingReason::kNotScrollingOnMain)
+      return 0;
+
+    uint32_t bucket = 1;
+    while ((reason = reason >> 1))
+      bucket++;
+    return bucket;
+  }
+
+ protected:
+  WebTouchEvent touch_start_;
+  WebTouchEvent touch_end_;
+  WebMouseWheelEvent wheel_event_;
+  WebGestureEvent gesture_scroll_begin_;
+  WebGestureEvent gesture_scroll_end_;
+};
+
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
+       GestureScrollNotScrollOnMain) {
+  // Touch start with passive event listener.
+  SetupEvents(TestEventType::Touch);
+
+  EXPECT_CALL(
+      mock_input_handler_,
+      EventListenerTypeForTouchStartOrMoveAt(
+          testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_))
+      .WillOnce(testing::Return(
+          cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
+  EXPECT_CALL(
+      mock_input_handler_,
+      GetEventListenerProperties(cc::EventListenerClass::kTouchStartOrMove))
+      .WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
+  EXPECT_CALL(mock_client_,
+              SetWhiteListedTouchAction(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return());
+
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(touch_start_));
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kImplThreadScrollState));
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_begin_));
+  EXPECT_THAT(
+      histogram_tester().GetAllSamples(
+          "Renderer4.MainThreadGestureScrollReason"),
+      testing::ElementsAre(base::Bucket(
+          GetBucketSample(cc::MainThreadScrollingReason::kNotScrollingOnMain),
+          1)));
+
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_end_));
+}
+
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
+       GestureScrollTouchEventHandlerRegion) {
+  // The touch event hits a touch event handler and should block on main thread.
+  // Since ScrollBegin allows the gesture to scroll on impl. We collect
+  // TouchEventHandler reason but not HandlingScrollFromMainThread.
+  SetupEvents(TestEventType::Touch);
+
+  EXPECT_CALL(
+      mock_input_handler_,
+      EventListenerTypeForTouchStartOrMoveAt(
+          testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_))
+      .WillOnce(
+          testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType::
+                              HANDLER_ON_SCROLLING_LAYER));
+  EXPECT_CALL(mock_client_,
+              SetWhiteListedTouchAction(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return());
+
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(touch_start_));
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kImplThreadScrollState));
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_begin_));
+  EXPECT_THAT(histogram_tester().GetAllSamples(
+                  "Renderer4.MainThreadGestureScrollReason"),
+              testing::ElementsAre(base::Bucket(
+                  GetBucketSample(
+                      cc::MainThreadScrollingReason::kTouchEventHandlerRegion),
+                  1)));
+
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_end_));
+}
+
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
+       GestureScrollTouchEventHandlerRegionAndHandlingScrollFromMainThread) {
+  // The touch event hits a touch event handler and should block on main thread.
+  // Since ScrollBegin doesn't allow the gesture to scroll on impl. We report
+  // TouchEventHandler reason as well as HandlingScrollFromMainThread. Since we
+  // do not collect HandlingScrollFromMainThread when there are other reasons
+  // present, TouchEventHandler is the only reason being collected in the
+  // histogram.
+  SetupEvents(TestEventType::Touch);
+
+  EXPECT_CALL(
+      mock_input_handler_,
+      EventListenerTypeForTouchStartOrMoveAt(
+          testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_))
+      .WillOnce(
+          testing::Return(cc::InputHandler::TouchStartOrMoveEventListenerType::
+                              HANDLER_ON_SCROLLING_LAYER));
+  EXPECT_CALL(mock_client_,
+              SetWhiteListedTouchAction(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return());
+
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(touch_start_));
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kMainThreadScrollState));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_begin_));
+
+  EXPECT_THAT(histogram_tester().GetAllSamples(
+                  "Renderer4.MainThreadGestureScrollReason"),
+              testing::ElementsAre(base::Bucket(
+                  GetBucketSample(
+                      cc::MainThreadScrollingReason::kTouchEventHandlerRegion),
+                  1)));
+
+  // Handle touch end event so that input handler proxy is out of the state of
+  // DID_NOT_HANDLE.
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_end_));
+
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(touch_end_));
+}
+
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
+       GestureScrollHandlingScrollFromMainThread) {
+  // Gesture scrolling on main thread. We only record
+  // HandlingScrollFromMainThread when it's the only available reason.
+  SetupEvents(TestEventType::Touch);
+  EXPECT_CALL(
+      mock_input_handler_,
+      EventListenerTypeForTouchStartOrMoveAt(
+          testing::Property(&gfx::Point::x, testing::Gt(0)), testing::_))
+      .WillOnce(testing::Return(
+          cc::InputHandler::TouchStartOrMoveEventListenerType::NO_HANDLER));
+  EXPECT_CALL(mock_client_,
+              SetWhiteListedTouchAction(testing::_, testing::_, testing::_))
+      .WillOnce(testing::Return());
+  EXPECT_CALL(mock_input_handler_, GetEventListenerProperties(testing::_))
+      .WillRepeatedly(testing::Return(cc::EventListenerProperties::kPassive));
+
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(touch_start_));
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kMainThreadScrollState));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_begin_));
+
+  EXPECT_THAT(
+      histogram_tester().GetAllSamples(
+          "Renderer4.MainThreadGestureScrollReason"),
+      testing::ElementsAre(base::Bucket(
+          GetBucketSample(
+              cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
+          1)));
+
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_end_));
+}
+
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest, WheelScrollHistogram) {
+  // Firstly check if input handler can correctly record main thread scrolling
+  // reasons.
+  input_handler_->RecordMainThreadScrollingReasonsForTest(
+      blink::kWebGestureDeviceTouchpad,
+      cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects |
+          cc::MainThreadScrollingReason::kThreadedScrollingDisabled |
+          cc::MainThreadScrollingReason::kPageOverlay |
+          cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
+
+  EXPECT_THAT(
+      histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
+      testing::ElementsAre(
+          base::Bucket(
+              GetBucketSample(cc::MainThreadScrollingReason::
+                                  kHasBackgroundAttachmentFixedObjects),
+              1),
+          base::Bucket(
+              GetBucketSample(
+                  cc::MainThreadScrollingReason::kThreadedScrollingDisabled),
+              1),
+          base::Bucket(
+              GetBucketSample(cc::MainThreadScrollingReason::kPageOverlay),
+              1)));
+
+  // We only want to record "Handling scroll from main thread" reason if it's
+  // the only reason. If it's not the only reason, the "real" reason for
+  // scrolling on main is something else, and we only want to pay attention to
+  // that reason. So we should only include this reason in the histogram when
+  // its on its own.
+  input_handler_->RecordMainThreadScrollingReasonsForTest(
+      blink::kWebGestureDeviceTouchpad,
+      cc::MainThreadScrollingReason::kHandlingScrollFromMainThread);
+
+  EXPECT_THAT(
+      histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
+      testing::ElementsAre(
+          base::Bucket(
+              GetBucketSample(cc::MainThreadScrollingReason::
+                                  kHasBackgroundAttachmentFixedObjects),
+              1),
+          base::Bucket(
+              GetBucketSample(
+                  cc::MainThreadScrollingReason::kThreadedScrollingDisabled),
+              1),
+          base::Bucket(
+              GetBucketSample(cc::MainThreadScrollingReason::kPageOverlay), 1),
+          base::Bucket(
+              GetBucketSample(
+                  cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
+              1)));
+}
+
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
+       WheelScrollNotScrollingOnMain) {
+  // Even if a scroller is composited, we still need to record its main thread
+  // scrolling reason if it is blocked on a main thread event handler.
+  SetupEvents(TestEventType::MouseWheel);
+
+  // We can scroll on impl for an wheel event with passive event listener.
+  EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_))
+      .WillRepeatedly(testing::Return(false));
+  EXPECT_CALL(mock_input_handler_,
+              GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
+      .WillOnce(testing::Return(cc::EventListenerProperties::kPassive));
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE_NON_BLOCKING;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(wheel_event_));
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kImplThreadScrollState));
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_begin_));
+
+  EXPECT_THAT(
+      histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
+      testing::ElementsAre(base::Bucket(
+          GetBucketSample(cc::MainThreadScrollingReason::kNotScrollingOnMain),
+          1)));
+
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_end_));
+}
+
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
+       WheelScrollWheelEventHandlerRegion) {
+  // Wheel event with blocking event listener. If there is a wheel event handler
+  // at the point, we do not need to call GetEventListenerProperties since it
+  // indicates kBlocking.
+  SetupEvents(TestEventType::MouseWheel);
+  EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_))
+      .WillRepeatedly(testing::Return(true));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(wheel_event_));
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kImplThreadScrollState));
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_begin_));
+
+  EXPECT_THAT(
+      histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
+      testing::ElementsAre(base::Bucket(
+          GetBucketSample(
+              cc::MainThreadScrollingReason::kWheelEventHandlerRegion),
+          1)));
+
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+  expected_disposition_ = InputHandlerProxy::DID_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_end_));
+}
+
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
+       WheelScrollWheelEventHandlerRegionAndHandlingScrollFromMainThread) {
+  // Wheel scrolling on main thread. Because we also block scrolling with wheel
+  // event handler, we should record that reason as well.
+  SetupEvents(TestEventType::MouseWheel);
+  EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_))
+      .WillRepeatedly(testing::Return(true));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(wheel_event_));
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kMainThreadScrollState));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_begin_));
+
+  EXPECT_THAT(
+      histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
+      testing::ElementsAre(base::Bucket(
+          GetBucketSample(
+              cc::MainThreadScrollingReason::kWheelEventHandlerRegion),
+          1)));
+
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_end_));
+}
+
+TEST_P(InputHandlerProxyMainThreadScrollingReasonTest,
+       WheelScrollHandlingScrollFromMainThread) {
+  // Gesture scrolling on main thread. We only record
+  // HandlingScrollFromMainThread when it's the only available reason.
+  SetupEvents(TestEventType::MouseWheel);
+  EXPECT_CALL(mock_input_handler_, HasBlockingWheelEventHandlerAt(testing::_))
+      .WillRepeatedly(testing::Return(false));
+  EXPECT_CALL(mock_input_handler_,
+              GetEventListenerProperties(cc::EventListenerClass::kMouseWheel))
+      .WillOnce(testing::Return(cc::EventListenerProperties::kNone));
+  expected_disposition_ = InputHandlerProxy::DROP_EVENT;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(wheel_event_));
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kMainThreadScrollState));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_begin_));
+
+  EXPECT_THAT(
+      histogram_tester().GetAllSamples("Renderer4.MainThreadWheelScrollReason"),
+      testing::ElementsAre(base::Bucket(
+          GetBucketSample(
+              cc::MainThreadScrollingReason::kHandlingScrollFromMainThread),
+          1)));
+
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_, true));
+  expected_disposition_ = InputHandlerProxy::DID_NOT_HANDLE;
+  EXPECT_EQ(expected_disposition_,
+            input_handler_->HandleInputEvent(gesture_scroll_end_));
+}
+
 INSTANTIATE_TEST_CASE_P(AnimateInput,
                         InputHandlerProxyTest,
                         testing::ValuesIn(test_types));
+
+INSTANTIATE_TEST_CASE_P(AnimateInput,
+                        InputHandlerProxyMainThreadScrollingReasonTest,
+                        testing::ValuesIn(test_types));
 }  // namespace test
 }  // namespace ui
diff --git a/ui/events/cocoa/events_mac.mm b/ui/events/cocoa/events_mac.mm
index c60c04c7..17d539b 100644
--- a/ui/events/cocoa/events_mac.mm
+++ b/ui/events/cocoa/events_mac.mm
@@ -63,6 +63,7 @@
     case NSEventTypeRotate:
     case NSEventTypeBeginGesture:
     case NSEventTypeEndGesture:
+    case NSEventTypePressure:
       break;
     default:
       NOTIMPLEMENTED() << type;
diff --git a/ui/latency/frame_metrics_test_common.h b/ui/latency/frame_metrics_test_common.h
index c48e814..30ed36d9 100644
--- a/ui/latency/frame_metrics_test_common.h
+++ b/ui/latency/frame_metrics_test_common.h
@@ -76,21 +76,6 @@
   }
 }
 
-// Same as AddPatternHelper, but uses each value (+1) as its own weight.
-// The "Cubed" name comes from the fact that the squared_accumulator
-// for the RMS will effectively be a "cubed accumulator".
-template <typename AnalyzerType>
-void AddCubedPatternHelper(SharedWindowedAnalyzerClient* shared_client,
-                           AnalyzerType* analyzer,
-                           const std::vector<uint32_t>& values) {
-  for (auto i : values) {
-    shared_client->window_begin += base::TimeDelta::FromMicroseconds(1);
-    shared_client->window_end += base::TimeDelta::FromMicroseconds(1);
-    // weight is i+1 to avoid divide by zero.
-    AddSamplesHelper(analyzer, i, i + 1, 1);
-  }
-}
-
 // Mean and RMS can be exact for most values, however SMR loses a bit of
 // precision internally when accumulating the roots. Make sure the SMR
 // precision is at least within .5 (i.e. rounded to the nearest integer
diff --git a/ui/latency/windowed_analyzer_unittest.cc b/ui/latency/windowed_analyzer_unittest.cc
index 71b4248..f60eb82 100644
--- a/ui/latency/windowed_analyzer_unittest.cc
+++ b/ui/latency/windowed_analyzer_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/time/time.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/latency/fixed_point.h"
 #include "ui/latency/frame_metrics_test_common.h"
 
 namespace ui {
@@ -351,6 +352,22 @@
     naive_total_weight_ += weight;
   }
 
+  // Same as AddPatternHelper, but uses each value (+1) as its own weight.
+  // The "Cubed" name comes from the fact that the squared_accumulator
+  // for the RMS will effectively be a "cubed accumulator".
+  void AddCubedPatternHelper(SharedWindowedAnalyzerClient* shared_client,
+                             const std::vector<uint32_t>& values) {
+    for (auto i : values) {
+      shared_client->window_begin += base::TimeDelta::FromMicroseconds(1);
+      shared_client->window_end += base::TimeDelta::FromMicroseconds(1);
+      uint64_t weighted_value = (i * (i + 1));
+      uint64_t updated_value = static_cast<uint64_t>(i);
+      uint64_t weighted_root = (i + 1) * std::sqrt(updated_value << 32);
+      Accumulator96b weighted_square(i, (i + 1));
+      AddSample(i, (i + 1), weighted_value, weighted_root, weighted_square);
+    }
+  }
+
   struct Sample {
     uint32_t value;
     uint32_t weight;
@@ -412,8 +429,8 @@
   double naive_root_accumulator_prev = 0;
   double naive_square_accumulator_prev = 0;
   for (size_t i = 1; i <= kRuns; i++) {
-    AddCubedPatternHelper(&shared_client_naive, &analyzer_naive, pattern_bad);
-    AddCubedPatternHelper(&shared_client_naive, &analyzer_naive, pattern_clear);
+    analyzer_naive.AddCubedPatternHelper(&shared_client_naive, pattern_bad);
+    analyzer_naive.AddCubedPatternHelper(&shared_client_naive, pattern_clear);
     EXPECT_EQ(0, analyzer_naive.naive_accumulator_);
     EXPECT_ABS_LT(naive_root_accumulator_prev,
                   analyzer_naive.naive_root_accumulator_);
@@ -427,15 +444,6 @@
                 analyzer_naive.naive_root_accumulator_);
   EXPECT_ABS_LE(naive_square_error_floor * kRuns,
                 analyzer_naive.naive_square_accumulator_);
-
-  // Verify actual implementation has no error.
-  for (size_t i = 1; i <= kRuns; i++) {
-    AddCubedPatternHelper(&shared_client_impl, &analyzer_impl, pattern_bad);
-    AddCubedPatternHelper(&shared_client_impl, &analyzer_impl, pattern_clear);
-    EXPECT_EQ(0, analyzer_impl.CurrentAccumulator());
-    EXPECT_EQ(0, analyzer_impl.CurrentRootAccumulator());
-    EXPECT_EQ(0, analyzer_impl.CurrentSquareAccumulator());
-  }
 }
 
 // This is a synthetic example that is just outside the dynamic range of a
diff --git a/ui/views/widget/native_widget_mac_unittest.mm b/ui/views/widget/native_widget_mac_unittest.mm
index c8293175..7436e30 100644
--- a/ui/views/widget/native_widget_mac_unittest.mm
+++ b/ui/views/widget/native_widget_mac_unittest.mm
@@ -1779,7 +1779,7 @@
 
   // The default window with a title should look different from the
   // window with an empty title.
-  EXPECT_FALSE([empty_title_data isEqualToData:this_title_data]);
+  EXPECT_NSNE(empty_title_data, this_title_data);
 
   delegate.set_should_show_title(false);
   delegate.set_title(base::ASCIIToUTF16("This is another title"));
@@ -1789,7 +1789,7 @@
   // With our magic setting, the window with a title should look the
   // same as the window with an empty title.
   EXPECT_TRUE([ns_window _isTitleHidden]);
-  EXPECT_TRUE([empty_title_data isEqualToData:hidden_title_data]);
+  EXPECT_NSEQ(empty_title_data, hidden_title_data);
 
   widget->CloseNow();
 }
@@ -2194,9 +2194,10 @@
       hosts_.push_back(std::move(holder));
     }
     EXPECT_EQ(kNativeViewCount, native_host_parent_->child_count());
-    EXPECT_TRUE(([[widget_->GetNativeView() subviews] isEqualToArray:@[
-      compositor_view_, hosts_[0]->view(), hosts_[1]->view(), hosts_[2]->view()
-    ]]));
+    EXPECT_NSEQ([widget_->GetNativeView() subviews], (@[
+                  compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
+                  hosts_[2]->view()
+                ]));
   }
 
   void TearDown() override {
@@ -2219,61 +2220,59 @@
 // z-order.
 TEST_F(NativeWidgetMacViewsOrderTest, NativeViewAttached) {
   hosts_[1]->Detach();
-  EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
-    compositor_view_, hosts_[0]->view(), hosts_[2]->view()
-  ]]));
+  EXPECT_NSEQ([GetContentNativeView() subviews],
+              (@[ compositor_view_, hosts_[0]->view(), hosts_[2]->view() ]));
 
   hosts_[1]->AttachNativeView();
-  EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
-    compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
-    hosts_[2]->view()
-  ]]));
+  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
+                compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
+                hosts_[2]->view()
+              ]));
 }
 
 // Tests that NativeViews order changes according to views::View hierarchy.
 TEST_F(NativeWidgetMacViewsOrderTest, ReorderViews) {
   native_host_parent_->ReorderChildView(hosts_[2]->host(), 1);
-  EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
-    compositor_view_, hosts_[0]->view(), hosts_[2]->view(),
-    hosts_[1]->view()
-  ]]));
+  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
+                compositor_view_, hosts_[0]->view(), hosts_[2]->view(),
+                hosts_[1]->view()
+              ]));
 
   native_host_parent_->RemoveChildView(hosts_[2]->host());
-  EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
-    compositor_view_, hosts_[0]->view(), hosts_[1]->view()
-  ]]));
+  EXPECT_NSEQ([GetContentNativeView() subviews],
+              (@[ compositor_view_, hosts_[0]->view(), hosts_[1]->view() ]));
 
   View* new_parent = new View();
   native_host_parent_->RemoveChildView(hosts_[1]->host());
   native_host_parent_->AddChildView(new_parent);
   new_parent->AddChildView(hosts_[1]->host());
   new_parent->AddChildView(hosts_[2]->host());
-  EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
-    compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
-    hosts_[2]->view()
-  ]]));
+  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
+                compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
+                hosts_[2]->view()
+              ]));
 
   native_host_parent_->ReorderChildView(new_parent, 0);
-  EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
-    compositor_view_, hosts_[1]->view(), hosts_[2]->view(),
-    hosts_[0]->view()
-  ]]));
+  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
+                compositor_view_, hosts_[1]->view(), hosts_[2]->view(),
+                hosts_[0]->view()
+              ]));
 }
 
 // Test that unassociated native views stay on top after reordering.
 TEST_F(NativeWidgetMacViewsOrderTest, UnassociatedViewsIsAbove) {
   base::scoped_nsobject<NSView> child_view([[NSView alloc] init]);
   [GetContentNativeView() addSubview:child_view];
-  EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
-    compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
-    hosts_[2]->view(), child_view
-  ]]));
+  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
+                compositor_view_, hosts_[0]->view(), hosts_[1]->view(),
+                hosts_[2]->view(), child_view
+              ]));
 
   native_host_parent_->ReorderChildView(hosts_[2]->host(), 1);
-  EXPECT_TRUE(([[GetContentNativeView() subviews] isEqualToArray:@[
-    compositor_view_, hosts_[0]->view(), hosts_[2]->view(),
-    hosts_[1]->view(), child_view
-  ]]));
+  EXPECT_NSEQ([GetContentNativeView() subviews], (@[
+                compositor_view_, hosts_[0]->view(), hosts_[2]->view(),
+                hosts_[1]->view(), child_view
+              ]));
 }
 
 // Test -[NSWindowDelegate windowShouldClose:].
diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc
index 314c562b..9ca4bdad 100644
--- a/ui/views/win/hwnd_message_handler.cc
+++ b/ui/views/win/hwnd_message_handler.cc
@@ -1000,12 +1000,14 @@
 
 void HWNDMessageHandler::OnCaretBoundsChanged(
     const ui::TextInputClient* client) {
-  if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
-    return;
-
   if (!ax_system_caret_)
     ax_system_caret_ = std::make_unique<ui::AXSystemCaretWin>(hwnd());
 
+  if (!client || client->GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) {
+    ax_system_caret_->Hide();
+    return;
+  }
+
   const gfx::Rect dip_caret_bounds(client->GetCaretBounds());
   gfx::Rect caret_bounds =
       display::win::ScreenWin::DIPToScreenRect(hwnd(), dip_caret_bounds);
diff --git a/webrunner/net_http/service/url_loader_impl.cc b/webrunner/net_http/service/url_loader_impl.cc
index 3cd7efd..343826ce 100644
--- a/webrunner/net_http/service/url_loader_impl.cc
+++ b/webrunner/net_http/service/url_loader_impl.cc
@@ -21,9 +21,8 @@
 // server responses.
 const size_t kReadCapacity = 1024;
 
-// Converts |buffer| into a URLBody with the body set to a sized buffer.
-oldhttp::URLBodyPtr BuildResponseBuffer(
-    scoped_refptr<net::GrowableIOBuffer> buffer) {
+// Converts |buffer| into a URLBody with the body set to a buffer.
+oldhttp::URLBodyPtr CreateURLBodyFromBuffer(net::GrowableIOBuffer* buffer) {
   oldhttp::URLBodyPtr body = oldhttp::URLBody::New();
 
   // The response buffer size is exactly the offset.
@@ -37,7 +36,7 @@
     ZX_DLOG(WARNING, result) << "zx_vmo_write";
     return nullptr;
   }
-  body->set_sized_buffer(std::move(mem_buffer));
+  body->set_buffer(std::move(mem_buffer));
 
   return body;
 }
@@ -84,18 +83,18 @@
 }
 
 std::unique_ptr<UploadDataStream> UploadDataStreamFromMemBuffer(
-    fuchsia::mem::Buffer sized_buffer) {
+    fuchsia::mem::Buffer mem_buffer) {
   // TODO(http://crbug.com/875534): Write a ZxMemBufferUploadStream class.
   std::unique_ptr<ChunkedUploadDataStream> upload_stream =
       std::make_unique<net::ChunkedUploadDataStream>(0);
 
   char buffer[kReadCapacity];
-  size_t size = sized_buffer.size;
+  size_t size = mem_buffer.size;
   size_t offset = 0;
   zx_status_t result = ZX_OK;
   while (offset != size) {
     size_t length = std::min(size - offset, kReadCapacity);
-    result = sized_buffer.vmo.read(buffer, offset, length);
+    result = mem_buffer.vmo.read(buffer, offset, length);
     if (result != ZX_OK) {
       ZX_DLOG(WARNING, result) << "zx_vmo_read";
       return nullptr;
@@ -153,8 +152,8 @@
       upload_stream =
           UploadDataStreamFromZxSocket(std::move(request.body->stream()));
     } else {
-      upload_stream = UploadDataStreamFromMemBuffer(
-          std::move(request.body->sized_buffer()));
+      upload_stream =
+          UploadDataStreamFromMemBuffer(std::move(request.body->buffer()));
     }
 
     if (!upload_stream) {
@@ -311,7 +310,7 @@
       // way to recover from a failed socket close.
       write_socket_ = zx::socket();
     } else {
-      DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::SIZED_BUFFER);
+      DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::BUFFER);
       std::move(done_callback_)(BuildResponse(result));
     }
     return false;
@@ -327,9 +326,9 @@
       write_socket_.write(ZX_SOCKET_SHUTDOWN_WRITE, nullptr, 0, nullptr);
       write_socket_ = zx::socket();
     } else {
-      DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::SIZED_BUFFER);
+      DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::BUFFER);
       // In buffer mode, build the response and call the callback.
-      oldhttp::URLBodyPtr body = BuildResponseBuffer(buffer_);
+      oldhttp::URLBodyPtr body = CreateURLBodyFromBuffer(buffer_.get());
       if (body) {
         oldhttp::URLResponse response = BuildResponse(result);
         response.body = std::move(body);
@@ -363,7 +362,7 @@
       return false;
     }
   } else {
-    DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::SIZED_BUFFER);
+    DCHECK_EQ(response_body_mode_, oldhttp::ResponseBodyMode::BUFFER);
     // In buffer mode, expand the buffer.
     buffer_->SetCapacity(buffer_->capacity() + result);
     buffer_->set_offset(buffer_->offset() + result);